Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/imgui/src/imgui_demo.cpp
7322 views
1
// dear imgui, v1.92.6 WIP
2
// (demo code)
3
4
// Help:
5
// - Read FAQ at http://dearimgui.com/faq
6
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7
// - Need help integrating Dear ImGui in your codebase?
8
// - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started
9
// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
10
// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
11
// Get the latest version at https://github.com/ocornut/imgui
12
13
// How to easily locate code?
14
// - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools
15
// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html
16
// - Find a visible string and search for it in the code!
17
18
//---------------------------------------------------
19
// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT!
20
//---------------------------------------------------
21
// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase:
22
// Think again! It is the most useful reference code that you and other coders will want to refer to and call.
23
// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app!
24
// Also include Metrics! ItemPicker! DebugLog! and other debug features.
25
// Removing this file from your project is hindering access to documentation for everyone in your team,
26
// likely leading you to poorer usage of the library.
27
// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
28
// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
29
// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
30
// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference.
31
// Thank you,
32
// -Your beloved friend, imgui_demo.cpp (which you won't delete)
33
34
//--------------------------------------------
35
// ABOUT THE MEANING OF THE 'static' KEYWORD:
36
//--------------------------------------------
37
// In this demo code, we frequently use 'static' variables inside functions.
38
// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function.
39
// Think of "static int n = 0;" as "global int n = 0;" !
40
// We do this IN THE DEMO because we want:
41
// - to gather code and data in the same place.
42
// - to make the demo source code faster to read, faster to change, smaller in size.
43
// - it is also a convenient way of storing simple UI related information as long as your function
44
// doesn't need to be reentrant or used in multiple threads.
45
// This might be a pattern you will want to use in your code, but most of the data you would be working
46
// with in a complex codebase is likely going to be stored outside your functions.
47
48
//-----------------------------------------
49
// ABOUT THE CODING STYLE OF OUR DEMO CODE
50
//-----------------------------------------
51
// The Demo code in this file is designed to be easy to copy-and-paste into your application!
52
// Because of this:
53
// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
54
// - We try to declare static variables in the local scope, as close as possible to the code using them.
55
// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
56
// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
57
// by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional
58
// and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
59
// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
60
61
// Navigating this file:
62
// - In Visual Studio: Ctrl+Comma ("Edit.GoToAll") can follow symbols inside comments, whereas Ctrl+F12 ("Edit.GoToImplementation") cannot.
63
// - In Visual Studio w/ Visual Assist installed: Alt+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
64
// - In VS Code, CLion, etc.: Ctrl+Click can follow symbols inside comments.
65
// - You can search/grep for all sections listed in the index to find the section.
66
67
/*
68
69
Index of this file:
70
71
// [SECTION] Forward Declarations
72
// [SECTION] Helpers
73
// [SECTION] Demo Window / ShowDemoWindow()
74
// [SECTION] DemoWindowMenuBar()
75
// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
76
// [SECTION] DemoWindowWidgetsBasic()
77
// [SECTION] DemoWindowWidgetsBullets()
78
// [SECTION] DemoWindowWidgetsCollapsingHeaders()
79
// [SECTION] DemoWindowWidgetsComboBoxes()
80
// [SECTION] DemoWindowWidgetsColorAndPickers()
81
// [SECTION] DemoWindowWidgetsDataTypes()
82
// [SECTION] DemoWindowWidgetsDisableBlocks()
83
// [SECTION] DemoWindowWidgetsDragAndDrop()
84
// [SECTION] DemoWindowWidgetsDragsAndSliders()
85
// [SECTION] DemoWindowWidgetsFonts()
86
// [SECTION] DemoWindowWidgetsImages()
87
// [SECTION] DemoWindowWidgetsListBoxes()
88
// [SECTION] DemoWindowWidgetsMultiComponents()
89
// [SECTION] DemoWindowWidgetsPlotting()
90
// [SECTION] DemoWindowWidgetsProgressBars()
91
// [SECTION] DemoWindowWidgetsQueryingStatuses()
92
// [SECTION] DemoWindowWidgetsSelectables()
93
// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect()
94
// [SECTION] DemoWindowWidgetsTabs()
95
// [SECTION] DemoWindowWidgetsText()
96
// [SECTION] DemoWindowWidgetsTextFilter()
97
// [SECTION] DemoWindowWidgetsTextInput()
98
// [SECTION] DemoWindowWidgetsTooltips()
99
// [SECTION] DemoWindowWidgetsTreeNodes()
100
// [SECTION] DemoWindowWidgetsVerticalSliders()
101
// [SECTION] DemoWindowWidgets()
102
// [SECTION] DemoWindowLayout()
103
// [SECTION] DemoWindowPopups()
104
// [SECTION] DemoWindowTables()
105
// [SECTION] DemoWindowInputs()
106
// [SECTION] About Window / ShowAboutWindow()
107
// [SECTION] Style Editor / ShowStyleEditor()
108
// [SECTION] User Guide / ShowUserGuide()
109
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
110
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
111
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
112
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
113
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
114
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
115
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
116
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
117
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
118
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
119
// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
120
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
121
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
122
// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
123
124
*/
125
126
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
127
#define _CRT_SECURE_NO_WARNINGS
128
#endif
129
130
#include "imgui.h"
131
#ifndef IMGUI_DISABLE
132
133
// System includes
134
#include <ctype.h> // toupper
135
#include <limits.h> // INT_MIN, INT_MAX
136
#include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
137
#include <stdio.h> // vsnprintf, sscanf, printf
138
#include <stdlib.h> // NULL, malloc, free, atoi
139
#include <stdint.h> // intptr_t
140
#if !defined(_MSC_VER) || _MSC_VER >= 1800
141
#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
142
#endif
143
#ifdef __EMSCRIPTEN__
144
#include <emscripten/version.h> // __EMSCRIPTEN_major__ etc.
145
#endif
146
147
// Visual Studio warnings
148
#ifdef _MSC_VER
149
#pragma warning (disable: 4127) // condition expression is constant
150
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
151
#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).
152
#endif
153
154
// Clang/GCC warnings with -Weverything
155
#if defined(__clang__)
156
#if __has_warning("-Wunknown-warning-option")
157
#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!
158
#endif
159
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
160
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
161
#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)
162
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type
163
#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int'
164
#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal
165
#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.
166
#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.
167
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
168
#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.
169
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
170
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
171
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
172
#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label
173
#elif defined(__GNUC__)
174
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
175
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
176
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
177
#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*'
178
#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure)
179
#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
180
#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
181
#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.
182
#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1
183
#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
184
#endif
185
186
// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
187
#ifdef _WIN32
188
#define IM_NEWLINE "\r\n"
189
#else
190
#define IM_NEWLINE "\n"
191
#endif
192
193
// Helpers
194
#if defined(_MSC_VER) && !defined(snprintf)
195
#define snprintf _snprintf
196
#endif
197
#if defined(_MSC_VER) && !defined(vsnprintf)
198
#define vsnprintf _vsnprintf
199
#endif
200
201
// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
202
#if !defined(PRId64) && defined(_MSC_VER)
203
#define PRId64 "I64d"
204
#define PRIu64 "I64u"
205
#elif !defined(PRId64)
206
#define PRId64 "lld"
207
#define PRIu64 "llu"
208
#endif
209
210
// Helpers macros
211
// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
212
// but making an exception here as those are largely simplifying code...
213
// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
214
#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B))
215
#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B))
216
#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
217
218
// Enforce cdecl calling convention for functions called by the standard library,
219
// in case compilation settings changed the default to e.g. __vectorcall
220
#ifndef IMGUI_CDECL
221
#ifdef _MSC_VER
222
#define IMGUI_CDECL __cdecl
223
#else
224
#define IMGUI_CDECL
225
#endif
226
#endif
227
228
//-----------------------------------------------------------------------------
229
// [SECTION] Forward Declarations
230
//-----------------------------------------------------------------------------
231
232
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
233
234
// Forward Declarations
235
struct ImGuiDemoWindowData;
236
static void ShowExampleAppMainMenuBar();
237
static void ShowExampleAppAssetsBrowser(bool* p_open);
238
static void ShowExampleAppConsole(bool* p_open);
239
static void ShowExampleAppCustomRendering(bool* p_open);
240
static void ShowExampleAppDocuments(bool* p_open);
241
static void ShowExampleAppLog(bool* p_open);
242
static void ShowExampleAppLayout(bool* p_open);
243
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data);
244
static void ShowExampleAppSimpleOverlay(bool* p_open);
245
static void ShowExampleAppAutoResize(bool* p_open);
246
static void ShowExampleAppConstrainedResize(bool* p_open);
247
static void ShowExampleAppFullscreen(bool* p_open);
248
static void ShowExampleAppLongText(bool* p_open);
249
static void ShowExampleAppWindowTitles(bool* p_open);
250
static void ShowExampleMenuFile();
251
252
// We split the contents of the big ShowDemoWindow() function into smaller functions
253
// (because the link time of very large functions tends to grow non-linearly)
254
static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data);
255
static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data);
256
static void DemoWindowLayout();
257
static void DemoWindowPopups();
258
static void DemoWindowTables();
259
static void DemoWindowColumns();
260
static void DemoWindowInputs();
261
262
// Helper tree functions used by Property Editor & Multi-Select demos
263
struct ExampleTreeNode;
264
static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent);
265
static void ExampleTree_DestroyNode(ExampleTreeNode* node);
266
267
//-----------------------------------------------------------------------------
268
// [SECTION] Helpers
269
//-----------------------------------------------------------------------------
270
271
// Helper to display a little (?) mark which shows a tooltip when hovered.
272
// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
273
static void HelpMarker(const char* desc)
274
{
275
ImGui::TextDisabled("(?)");
276
if (ImGui::BeginItemTooltip())
277
{
278
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
279
ImGui::TextUnformatted(desc);
280
ImGui::PopTextWrapPos();
281
ImGui::EndTooltip();
282
}
283
}
284
285
// Helper to wire demo markers located in code to an interactive browser
286
typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
287
extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback;
288
extern void* GImGuiDemoMarkerCallbackUserData;
289
ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL;
290
void* GImGuiDemoMarkerCallbackUserData = NULL;
291
#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback("imgui_demo.cpp", __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
292
293
//-----------------------------------------------------------------------------
294
// [SECTION] Demo Window / ShowDemoWindow()
295
//-----------------------------------------------------------------------------
296
297
// Data to be shared across different functions of the demo.
298
struct ImGuiDemoWindowData
299
{
300
// Examples Apps (accessible from the "Examples" menu)
301
bool ShowMainMenuBar = false;
302
bool ShowAppAssetsBrowser = false;
303
bool ShowAppConsole = false;
304
bool ShowAppCustomRendering = false;
305
bool ShowAppDocuments = false;
306
bool ShowAppLog = false;
307
bool ShowAppLayout = false;
308
bool ShowAppPropertyEditor = false;
309
bool ShowAppSimpleOverlay = false;
310
bool ShowAppAutoResize = false;
311
bool ShowAppConstrainedResize = false;
312
bool ShowAppFullscreen = false;
313
bool ShowAppLongText = false;
314
bool ShowAppWindowTitles = false;
315
316
// Dear ImGui Tools (accessible from the "Tools" menu)
317
bool ShowMetrics = false;
318
bool ShowDebugLog = false;
319
bool ShowIDStackTool = false;
320
bool ShowStyleEditor = false;
321
bool ShowAbout = false;
322
323
// Other data
324
bool DisableSections = false;
325
ExampleTreeNode* DemoTree = NULL;
326
327
~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); }
328
};
329
330
// Demonstrate most Dear ImGui features (this is big function!)
331
// You may execute this function to experiment with the UI and understand what it does.
332
// You may then search for keywords in the code when you are interested by a specific feature.
333
void ImGui::ShowDemoWindow(bool* p_open)
334
{
335
// Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
336
// Most functions would normally just assert/crash if the context is missing.
337
IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
338
339
// Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
340
IMGUI_CHECKVERSION();
341
342
// Stored data
343
static ImGuiDemoWindowData demo_data;
344
345
// Examples Apps (accessible from the "Examples" menu)
346
if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); }
347
if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); }
348
if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
349
if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
350
if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
351
if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); }
352
if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
353
if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
354
if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); }
355
if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); }
356
if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); }
357
if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); }
358
if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); }
359
if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); }
360
361
// Dear ImGui Tools (accessible from the "Tools" menu)
362
if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); }
363
if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); }
364
if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); }
365
if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); }
366
if (demo_data.ShowStyleEditor)
367
{
368
ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor);
369
ImGui::ShowStyleEditor();
370
ImGui::End();
371
}
372
373
// Demonstrate the various window flags. Typically you would just use the default!
374
static bool no_titlebar = false;
375
static bool no_scrollbar = false;
376
static bool no_menu = false;
377
static bool no_move = false;
378
static bool no_resize = false;
379
static bool no_collapse = false;
380
static bool no_close = false;
381
static bool no_nav = false;
382
static bool no_background = false;
383
static bool no_bring_to_front = false;
384
static bool unsaved_document = false;
385
386
ImGuiWindowFlags window_flags = 0;
387
if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
388
if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
389
if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
390
if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
391
if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
392
if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
393
if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
394
if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
395
if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
396
if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
397
if (no_close) p_open = NULL; // Don't pass our bool* to Begin
398
399
// We specify a default position/size in case there's no data in the .ini file.
400
// We only do it to make the demo applications a little more welcoming, but typically this isn't required.
401
const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
402
ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
403
ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
404
405
// Main body of the Demo window starts here.
406
if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
407
{
408
// Early out if the window is collapsed, as an optimization.
409
ImGui::End();
410
return;
411
}
412
413
// Most framed widgets share a common width settings. Remaining width is used for the label.
414
// The width of the frame may be changed with PushItemWidth() or SetNextItemWidth().
415
// - Positive value for absolute size, negative value for right-alignment.
416
// - The default value is about GetWindowWidth() * 0.65f.
417
// - See 'Demo->Layout->Widgets Width' for details.
418
// Here we change the frame width based on how much width we want to give to the label.
419
const float label_width_base = ImGui::GetFontSize() * 12; // Some amount of width for label, based on font size.
420
const float label_width_max = ImGui::GetContentRegionAvail().x * 0.40f; // ...but always leave some room for framed widgets.
421
const float label_width = IM_MIN(label_width_base, label_width_max);
422
ImGui::PushItemWidth(-label_width); // Right-align: framed items will leave 'label_width' available for the label.
423
//ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use 40% width for framed widgets, leaving 60% width for labels.
424
//ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use 40% width for labels, leaving 60% width for framed widgets.
425
//ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Use XXX width for labels, leaving the rest for framed widgets.
426
427
// Menu Bar
428
DemoWindowMenuBar(&demo_data);
429
430
ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
431
ImGui::Spacing();
432
433
IMGUI_DEMO_MARKER("Help");
434
if (ImGui::CollapsingHeader("Help"))
435
{
436
ImGui::SeparatorText("ABOUT THIS DEMO:");
437
ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
438
ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
439
ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
440
"and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
441
442
ImGui::SeparatorText("PROGRAMMER GUIDE:");
443
ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
444
ImGui::BulletText("See comments in imgui.cpp.");
445
ImGui::BulletText("See example applications in the examples/ folder.");
446
ImGui::BulletText("Read the FAQ at ");
447
ImGui::SameLine(0, 0);
448
ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/");
449
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
450
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
451
452
ImGui::SeparatorText("USER GUIDE:");
453
ImGui::ShowUserGuide();
454
}
455
456
IMGUI_DEMO_MARKER("Configuration");
457
if (ImGui::CollapsingHeader("Configuration"))
458
{
459
ImGuiIO& io = ImGui::GetIO();
460
461
if (ImGui::TreeNode("Configuration##2"))
462
{
463
ImGui::SeparatorText("General");
464
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
465
ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
466
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
467
ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
468
ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
469
ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
470
471
// The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
472
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
473
{
474
if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
475
{
476
ImGui::SameLine();
477
ImGui::Text("<<PRESS SPACE TO DISABLE>>");
478
}
479
// Prevent both being checked
480
if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
481
io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
482
}
483
484
ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
485
ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
486
ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
487
ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
488
489
ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
490
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.");
491
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
492
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).");
493
494
ImGui::SeparatorText("Keyboard/Gamepad Navigation");
495
ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
496
ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos);
497
ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult");
498
ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard);
499
ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem);
500
ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
501
ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
502
ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window.");
503
ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto);
504
ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.");
505
ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
506
ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
507
508
ImGui::SeparatorText("Windows");
509
ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
510
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.");
511
ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
512
ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL]
513
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.");
514
ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage);
515
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.");
516
517
ImGui::SeparatorText("Widgets");
518
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
519
ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
520
ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
521
ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only).");
522
ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
523
ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
524
ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
525
ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
526
ImGui::Text("Also see Style->Rendering for rendering options.");
527
528
// Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
529
ImGui::SeparatorText("Error Handling");
530
531
ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery);
532
ImGui::SameLine(); HelpMarker(
533
"Options to configure how we handle recoverable errors.\n"
534
"- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n"
535
"- You not are not supposed to rely on it in the course of a normal application run.\n"
536
"- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n"
537
"- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! "
538
"Otherwise it would severely hinder your ability to catch and correct mistakes!");
539
ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert);
540
ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog);
541
ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip);
542
if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip)
543
io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true;
544
545
// Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools
546
ImGui::SeparatorText("Debug");
547
ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
548
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.");
549
ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
550
ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
551
ImGui::BeginDisabled();
552
ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
553
ImGui::EndDisabled();
554
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.");
555
ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
556
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.");
557
ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
558
ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
559
ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
560
ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
561
562
ImGui::TreePop();
563
ImGui::Spacing();
564
}
565
566
IMGUI_DEMO_MARKER("Configuration/Backend Flags");
567
if (ImGui::TreeNode("Backend Flags"))
568
{
569
HelpMarker(
570
"Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
571
"Here we expose them as read-only fields to avoid breaking interactions with your backend.");
572
573
// FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
574
ImGui::BeginDisabled();
575
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
576
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
577
ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
578
ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
579
ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures);
580
ImGui::EndDisabled();
581
582
ImGui::TreePop();
583
ImGui::Spacing();
584
}
585
586
IMGUI_DEMO_MARKER("Configuration/Style, Fonts");
587
if (ImGui::TreeNode("Style, Fonts"))
588
{
589
ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor);
590
ImGui::SameLine();
591
HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
592
ImGui::TreePop();
593
ImGui::Spacing();
594
}
595
596
IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
597
if (ImGui::TreeNode("Capture/Logging"))
598
{
599
HelpMarker(
600
"The logging API redirects all text output so you can easily capture the content of "
601
"a window or a block. Tree nodes can be automatically expanded.\n"
602
"Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
603
ImGui::LogButtons();
604
605
HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
606
if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
607
{
608
ImGui::LogToClipboard();
609
ImGui::LogText("Hello, world!");
610
ImGui::LogFinish();
611
}
612
ImGui::TreePop();
613
}
614
}
615
616
IMGUI_DEMO_MARKER("Window options");
617
if (ImGui::CollapsingHeader("Window options"))
618
{
619
if (ImGui::BeginTable("split", 3))
620
{
621
ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
622
ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
623
ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
624
ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
625
ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
626
ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
627
ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
628
ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
629
ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
630
ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
631
ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
632
ImGui::EndTable();
633
}
634
}
635
636
// All demo contents
637
DemoWindowWidgets(&demo_data);
638
DemoWindowLayout();
639
DemoWindowPopups();
640
DemoWindowTables();
641
DemoWindowInputs();
642
643
// End of ShowDemoWindow()
644
ImGui::PopItemWidth();
645
ImGui::End();
646
}
647
648
//-----------------------------------------------------------------------------
649
// [SECTION] DemoWindowMenuBar()
650
//-----------------------------------------------------------------------------
651
652
static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
653
{
654
IMGUI_DEMO_MARKER("Menu");
655
if (ImGui::BeginMenuBar())
656
{
657
if (ImGui::BeginMenu("Menu"))
658
{
659
IMGUI_DEMO_MARKER("Menu/File");
660
ShowExampleMenuFile();
661
ImGui::EndMenu();
662
}
663
if (ImGui::BeginMenu("Examples"))
664
{
665
IMGUI_DEMO_MARKER("Menu/Examples");
666
ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar);
667
668
ImGui::SeparatorText("Mini apps");
669
ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser);
670
ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
671
ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
672
ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
673
ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
674
ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
675
ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
676
ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay);
677
678
ImGui::SeparatorText("Concepts");
679
ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize);
680
ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize);
681
ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen);
682
ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText);
683
ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles);
684
685
ImGui::EndMenu();
686
}
687
//if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
688
if (ImGui::BeginMenu("Tools"))
689
{
690
IMGUI_DEMO_MARKER("Menu/Tools");
691
ImGuiIO& io = ImGui::GetIO();
692
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
693
const bool has_debug_tools = true;
694
#else
695
const bool has_debug_tools = false;
696
#endif
697
ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
698
if (ImGui::BeginMenu("Debug Options"))
699
{
700
ImGui::BeginDisabled(!has_debug_tools);
701
ImGui::Checkbox("Highlight ID Conflicts", &io.ConfigDebugHighlightIdConflicts);
702
ImGui::EndDisabled();
703
ImGui::Checkbox("Assert on error recovery", &io.ConfigErrorRecoveryEnableAssert);
704
ImGui::TextDisabled("(see Demo->Configuration for details & more)");
705
ImGui::EndMenu();
706
}
707
ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
708
ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
709
bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
710
if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools))// && is_debugger_present))
711
ImGui::DebugStartItemPicker();
712
if (!is_debugger_present)
713
ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application.");
714
ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
715
ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
716
717
ImGui::EndMenu();
718
}
719
ImGui::EndMenuBar();
720
}
721
}
722
723
//-----------------------------------------------------------------------------
724
// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
725
//-----------------------------------------------------------------------------
726
727
// Simple representation for a tree
728
// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.)
729
struct ExampleTreeNode
730
{
731
// Tree structure
732
char Name[28] = "";
733
int UID = 0;
734
ExampleTreeNode* Parent = NULL;
735
ImVector<ExampleTreeNode*> Childs;
736
unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily
737
738
// Leaf Data
739
bool HasData = false; // All leaves have data
740
bool DataMyBool = true;
741
int DataMyInt = 128;
742
ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f);
743
};
744
745
// Simple representation of struct metadata/serialization data.
746
// (this is a minimal version of what a typical advanced application may provide)
747
struct ExampleMemberInfo
748
{
749
const char* Name; // Member name
750
ImGuiDataType DataType; // Member type
751
int DataCount; // Member count (1 when scalar)
752
int Offset; // Offset inside parent structure
753
};
754
755
// Metadata description of ExampleTreeNode struct.
756
static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]
757
{
758
{ "MyName", ImGuiDataType_String, 1, offsetof(ExampleTreeNode, Name) },
759
{ "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) },
760
{ "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) },
761
{ "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) },
762
};
763
764
static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent)
765
{
766
ExampleTreeNode* node = IM_NEW(ExampleTreeNode);
767
snprintf(node->Name, IM_COUNTOF(node->Name), "%s", name);
768
node->UID = uid;
769
node->Parent = parent;
770
node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0;
771
if (parent)
772
parent->Childs.push_back(node);
773
return node;
774
}
775
776
static void ExampleTree_DestroyNode(ExampleTreeNode* node)
777
{
778
for (ExampleTreeNode* child_node : node->Childs)
779
ExampleTree_DestroyNode(child_node);
780
IM_DELETE(node);
781
}
782
783
// Create example tree data
784
// (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
785
static ExampleTreeNode* ExampleTree_CreateDemoTree()
786
{
787
static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
788
const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
789
char name_buf[NAME_MAX_LEN];
790
int uid = 0;
791
ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
792
const int root_items_multiplier = 2;
793
for (int idx_L0 = 0; idx_L0 < IM_COUNTOF(root_names) * root_items_multiplier; idx_L0++)
794
{
795
snprintf(name_buf, IM_COUNTOF(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier);
796
ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
797
const int number_of_childs = (int)strlen(node_L1->Name);
798
for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
799
{
800
snprintf(name_buf, IM_COUNTOF(name_buf), "Child %d", idx_L1);
801
ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1);
802
node_L2->HasData = true;
803
if (idx_L1 == 0)
804
{
805
snprintf(name_buf, IM_COUNTOF(name_buf), "Sub-child %d", 0);
806
ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2);
807
node_L3->HasData = true;
808
}
809
}
810
}
811
return node_L0;
812
}
813
814
//-----------------------------------------------------------------------------
815
// [SECTION] DemoWindowWidgetsBasic()
816
//-----------------------------------------------------------------------------
817
818
static void DemoWindowWidgetsBasic()
819
{
820
IMGUI_DEMO_MARKER("Widgets/Basic");
821
if (ImGui::TreeNode("Basic"))
822
{
823
ImGui::SeparatorText("General");
824
825
IMGUI_DEMO_MARKER("Widgets/Basic/Button");
826
static int clicked = 0;
827
if (ImGui::Button("Button"))
828
clicked++;
829
if (clicked & 1)
830
{
831
ImGui::SameLine();
832
ImGui::Text("Thanks for clicking me!");
833
}
834
835
IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
836
static bool check = true;
837
ImGui::Checkbox("checkbox", &check);
838
839
IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
840
static int e = 0;
841
ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
842
ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
843
ImGui::RadioButton("radio c", &e, 2);
844
845
ImGui::AlignTextToFramePadding();
846
ImGui::TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling");
847
848
// Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
849
IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
850
for (int i = 0; i < 7; i++)
851
{
852
if (i > 0)
853
ImGui::SameLine();
854
ImGui::PushID(i);
855
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
856
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
857
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
858
ImGui::Button("Click");
859
ImGui::PopStyleColor(3);
860
ImGui::PopID();
861
}
862
863
// Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
864
// (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
865
// See 'Demo->Layout->Text Baseline Alignment' for details.
866
ImGui::AlignTextToFramePadding();
867
ImGui::Text("Hold to repeat:");
868
ImGui::SameLine();
869
870
// Arrow buttons with Repeater
871
IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
872
static int counter = 0;
873
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
874
ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
875
if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
876
ImGui::SameLine(0.0f, spacing);
877
if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
878
ImGui::PopItemFlag();
879
ImGui::SameLine();
880
ImGui::Text("%d", counter);
881
882
ImGui::Button("Tooltip");
883
ImGui::SetItemTooltip("I am a tooltip");
884
885
ImGui::LabelText("label", "Value");
886
887
ImGui::SeparatorText("Inputs");
888
889
{
890
// If you want to use InputText() with std::string or any custom dynamic string type:
891
// - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp
892
// - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize.
893
IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
894
static char str0[128] = "Hello, world!";
895
ImGui::InputText("input text", str0, IM_COUNTOF(str0));
896
ImGui::SameLine(); HelpMarker(
897
"USER:\n"
898
"Hold Shift or use mouse to select text.\n"
899
"Ctrl+Left/Right to word jump.\n"
900
"Ctrl+A or Double-Click to select all.\n"
901
"Ctrl+X,Ctrl+C,Ctrl+V for clipboard.\n"
902
"Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.\n"
903
"Escape to revert.\n\n"
904
"PROGRAMMER:\n"
905
"You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
906
"to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
907
"in imgui_demo.cpp).");
908
909
static char str1[128] = "";
910
ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_COUNTOF(str1));
911
912
IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
913
static int i0 = 123;
914
ImGui::InputInt("input int", &i0);
915
916
static float f0 = 0.001f;
917
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
918
919
static double d0 = 999999.00000001;
920
ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
921
922
static float f1 = 1.e10f;
923
ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
924
ImGui::SameLine(); HelpMarker(
925
"You can input value using the scientific notation,\n"
926
" e.g. \"1e+8\" becomes \"100000000\".");
927
928
static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
929
ImGui::InputFloat3("input float3", vec4a);
930
}
931
932
ImGui::SeparatorText("Drags");
933
934
{
935
IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
936
static int i1 = 50, i2 = 42, i3 = 128;
937
ImGui::DragInt("drag int", &i1, 1);
938
ImGui::SameLine(); HelpMarker(
939
"Click and drag to edit value.\n"
940
"Hold Shift/Alt for faster/slower edit.\n"
941
"Double-Click or Ctrl+Click to input value.");
942
ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
943
ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
944
945
static float f1 = 1.00f, f2 = 0.0067f;
946
ImGui::DragFloat("drag float", &f1, 0.005f);
947
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
948
//ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
949
}
950
951
ImGui::SeparatorText("Sliders");
952
953
{
954
IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
955
static int i1 = 0;
956
ImGui::SliderInt("slider int", &i1, -1, 3);
957
ImGui::SameLine(); HelpMarker("Ctrl+Click to input value.");
958
959
static float f1 = 0.123f, f2 = 0.0f;
960
ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
961
ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
962
963
IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
964
static float angle = 0.0f;
965
ImGui::SliderAngle("slider angle", &angle);
966
967
// Using the format string to display a name instead of an integer.
968
// Here we completely omit '%d' from the format string, so it'll only display a name.
969
// This technique can also be used with DragInt().
970
IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
971
enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
972
static int elem = Element_Fire;
973
const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
974
const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
975
ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable Ctrl+Click here.
976
ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
977
}
978
979
ImGui::SeparatorText("Selectors/Pickers");
980
981
{
982
IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
983
static float col1[3] = { 1.0f, 0.0f, 0.2f };
984
static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
985
ImGui::ColorEdit3("color 1", col1);
986
ImGui::SameLine(); HelpMarker(
987
"Click on the color square to open a color picker.\n"
988
"Click and hold to use drag and drop.\n"
989
"Right-Click on the color square to show options.\n"
990
"Ctrl+Click on individual component to input value.\n");
991
992
ImGui::ColorEdit4("color 2", col2);
993
}
994
995
{
996
// Using the _simplified_ one-liner Combo() api here
997
// See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
998
IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
999
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
1000
static int item_current = 0;
1001
ImGui::Combo("combo", &item_current, items, IM_COUNTOF(items));
1002
ImGui::SameLine(); HelpMarker(
1003
"Using the simplified one-liner Combo API here.\n"
1004
"Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
1005
}
1006
1007
{
1008
// Using the _simplified_ one-liner ListBox() api here
1009
// See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
1010
IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
1011
const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
1012
static int item_current = 1;
1013
ImGui::ListBox("listbox", &item_current, items, IM_COUNTOF(items), 4);
1014
ImGui::SameLine(); HelpMarker(
1015
"Using the simplified one-liner ListBox API here.\n"
1016
"Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
1017
}
1018
1019
// Testing ImGuiOnceUponAFrame helper.
1020
//static ImGuiOnceUponAFrame once;
1021
//for (int i = 0; i < 5; i++)
1022
// if (once)
1023
// ImGui::Text("This will be displayed only once.");
1024
1025
ImGui::TreePop();
1026
}
1027
}
1028
1029
//-----------------------------------------------------------------------------
1030
// [SECTION] DemoWindowWidgetsBullets()
1031
//-----------------------------------------------------------------------------
1032
1033
static void DemoWindowWidgetsBullets()
1034
{
1035
IMGUI_DEMO_MARKER("Widgets/Bullets");
1036
if (ImGui::TreeNode("Bullets"))
1037
{
1038
ImGui::BulletText("Bullet point 1");
1039
ImGui::BulletText("Bullet point 2\nOn multiple lines");
1040
if (ImGui::TreeNode("Tree node"))
1041
{
1042
ImGui::BulletText("Another bullet point");
1043
ImGui::TreePop();
1044
}
1045
ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
1046
ImGui::Bullet(); ImGui::SmallButton("Button");
1047
ImGui::TreePop();
1048
}
1049
}
1050
1051
//-----------------------------------------------------------------------------
1052
// [SECTION] DemoWindowWidgetsCollapsingHeaders()
1053
//-----------------------------------------------------------------------------
1054
1055
static void DemoWindowWidgetsCollapsingHeaders()
1056
{
1057
IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1058
if (ImGui::TreeNode("Collapsing Headers"))
1059
{
1060
static bool closable_group = true;
1061
ImGui::Checkbox("Show 2nd header", &closable_group);
1062
if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
1063
{
1064
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1065
for (int i = 0; i < 5; i++)
1066
ImGui::Text("Some content %d", i);
1067
}
1068
if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
1069
{
1070
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1071
for (int i = 0; i < 5; i++)
1072
ImGui::Text("More content %d", i);
1073
}
1074
/*
1075
if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1076
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1077
*/
1078
ImGui::TreePop();
1079
}
1080
}
1081
1082
//-----------------------------------------------------------------------------
1083
// [SECTION] DemoWindowWidgetsColorAndPickers()
1084
//-----------------------------------------------------------------------------
1085
1086
static void DemoWindowWidgetsColorAndPickers()
1087
{
1088
IMGUI_DEMO_MARKER("Widgets/Color");
1089
if (ImGui::TreeNode("Color/Picker Widgets"))
1090
{
1091
static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
1092
static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_None;
1093
1094
ImGui::SeparatorText("Options");
1095
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha);
1096
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque);
1097
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg);
1098
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
1099
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
1100
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop);
1101
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoColorMarkers", &base_flags, ImGuiColorEditFlags_NoColorMarkers);
1102
ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
1103
1104
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
1105
ImGui::SeparatorText("Inline color editor");
1106
ImGui::Text("Color widget:");
1107
ImGui::SameLine(); HelpMarker(
1108
"Click on the color square to open a color picker.\n"
1109
"Ctrl+Click on individual component to input value.\n");
1110
ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags);
1111
1112
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
1113
ImGui::Text("Color widget HSV with Alpha:");
1114
ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags);
1115
1116
IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
1117
ImGui::Text("Color widget with Float Display:");
1118
ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags);
1119
1120
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
1121
ImGui::Text("Color button with Picker:");
1122
ImGui::SameLine(); HelpMarker(
1123
"With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
1124
"With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
1125
"be used for the tooltip and picker popup.");
1126
ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags);
1127
1128
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
1129
ImGui::Text("Color button with Custom Picker Popup:");
1130
1131
// Generate a default palette. The palette will persist and can be edited.
1132
static bool saved_palette_init = true;
1133
static ImVec4 saved_palette[32] = {};
1134
if (saved_palette_init)
1135
{
1136
for (int n = 0; n < IM_COUNTOF(saved_palette); n++)
1137
{
1138
ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
1139
saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
1140
saved_palette[n].w = 1.0f; // Alpha
1141
}
1142
saved_palette_init = false;
1143
}
1144
1145
static ImVec4 backup_color;
1146
bool open_popup = ImGui::ColorButton("MyColor##3b", color, base_flags);
1147
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
1148
open_popup |= ImGui::Button("Palette");
1149
if (open_popup)
1150
{
1151
ImGui::OpenPopup("mypicker");
1152
backup_color = color;
1153
}
1154
if (ImGui::BeginPopup("mypicker"))
1155
{
1156
ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
1157
ImGui::Separator();
1158
ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
1159
ImGui::SameLine();
1160
1161
ImGui::BeginGroup(); // Lock X position
1162
ImGui::Text("Current");
1163
ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
1164
ImGui::Text("Previous");
1165
if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
1166
color = backup_color;
1167
ImGui::Separator();
1168
ImGui::Text("Palette");
1169
for (int n = 0; n < IM_COUNTOF(saved_palette); n++)
1170
{
1171
ImGui::PushID(n);
1172
if ((n % 8) != 0)
1173
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
1174
1175
ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
1176
if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
1177
color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
1178
1179
// Allow user to drop colors into each palette entry. Note that ColorButton() is already a
1180
// drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
1181
if (ImGui::BeginDragDropTarget())
1182
{
1183
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
1184
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
1185
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
1186
memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
1187
ImGui::EndDragDropTarget();
1188
}
1189
1190
ImGui::PopID();
1191
}
1192
ImGui::EndGroup();
1193
ImGui::EndPopup();
1194
}
1195
1196
IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
1197
ImGui::Text("Color button only:");
1198
static bool no_border = false;
1199
ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
1200
ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
1201
1202
IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
1203
ImGui::SeparatorText("Color picker");
1204
1205
static bool ref_color = false;
1206
static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
1207
static int picker_mode = 0;
1208
static int display_mode = 0;
1209
static ImGuiColorEditFlags color_picker_flags = ImGuiColorEditFlags_AlphaBar;
1210
1211
ImGui::PushID("Color picker");
1212
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha);
1213
ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar);
1214
ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview);
1215
if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview)
1216
{
1217
ImGui::SameLine();
1218
ImGui::Checkbox("With Ref Color", &ref_color);
1219
if (ref_color)
1220
{
1221
ImGui::SameLine();
1222
ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags);
1223
}
1224
}
1225
1226
ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0");
1227
ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode.");
1228
1229
ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0");
1230
ImGui::SameLine(); HelpMarker(
1231
"ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
1232
"but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
1233
"if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
1234
1235
ImGuiColorEditFlags flags = base_flags | color_picker_flags;
1236
if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
1237
if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
1238
if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
1239
if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
1240
if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
1241
if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
1242
ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
1243
1244
ImGui::Text("Set defaults in code:");
1245
ImGui::SameLine(); HelpMarker(
1246
"SetColorEditOptions() is designed to allow you to set boot-time default.\n"
1247
"We don't have Push/Pop functions because you can force options on a per-widget basis if needed, "
1248
"and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid "
1249
"encouraging you to persistently save values that aren't forward-compatible.");
1250
if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
1251
ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
1252
if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
1253
ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
1254
1255
// Always display a small version of both types of pickers
1256
// (that's in order to make it more visible in the demo to people who are skimming quickly through it)
1257
ImGui::Text("Both types:");
1258
float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
1259
ImGui::SetNextItemWidth(w);
1260
ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
1261
ImGui::SameLine();
1262
ImGui::SetNextItemWidth(w);
1263
ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
1264
ImGui::PopID();
1265
1266
// HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
1267
static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
1268
ImGui::Spacing();
1269
ImGui::Text("HSV encoded colors");
1270
ImGui::SameLine(); HelpMarker(
1271
"By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV "
1272
"allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the "
1273
"added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
1274
ImGui::Text("Color widget with InputHSV:");
1275
ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1276
ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1277
ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
1278
1279
ImGui::TreePop();
1280
}
1281
}
1282
1283
//-----------------------------------------------------------------------------
1284
// [SECTION] DemoWindowWidgetsComboBoxes()
1285
//-----------------------------------------------------------------------------
1286
1287
static void DemoWindowWidgetsComboBoxes()
1288
{
1289
IMGUI_DEMO_MARKER("Widgets/Combo");
1290
if (ImGui::TreeNode("Combo"))
1291
{
1292
// Combo Boxes are also called "Dropdown" in other systems
1293
// Expose flags as checkbox for the demo
1294
static ImGuiComboFlags flags = 0;
1295
ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1296
ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1297
if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1298
flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags
1299
if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1300
flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1301
if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
1302
flags &= ~ImGuiComboFlags_NoPreview;
1303
1304
// Override default popup height
1305
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
1306
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1307
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
1308
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1309
if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
1310
flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1311
1312
// Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1313
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1314
// stored in the object itself, etc.)
1315
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1316
static int item_selected_idx = 0; // Here we store our selection data as an index.
1317
1318
// Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1319
const char* combo_preview_value = items[item_selected_idx];
1320
if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1321
{
1322
for (int n = 0; n < IM_COUNTOF(items); n++)
1323
{
1324
const bool is_selected = (item_selected_idx == n);
1325
if (ImGui::Selectable(items[n], is_selected))
1326
item_selected_idx = n;
1327
1328
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1329
if (is_selected)
1330
ImGui::SetItemDefaultFocus();
1331
}
1332
ImGui::EndCombo();
1333
}
1334
1335
// Show case embedding a filter using a simple trick: displaying the filter inside combo contents.
1336
// See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives.
1337
if (ImGui::BeginCombo("combo 2 (w/ filter)", combo_preview_value, flags))
1338
{
1339
static ImGuiTextFilter filter;
1340
if (ImGui::IsWindowAppearing())
1341
{
1342
ImGui::SetKeyboardFocusHere();
1343
filter.Clear();
1344
}
1345
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F);
1346
filter.Draw("##Filter", -FLT_MIN);
1347
1348
for (int n = 0; n < IM_COUNTOF(items); n++)
1349
{
1350
const bool is_selected = (item_selected_idx == n);
1351
if (filter.PassFilter(items[n]))
1352
if (ImGui::Selectable(items[n], is_selected))
1353
item_selected_idx = n;
1354
}
1355
ImGui::EndCombo();
1356
}
1357
1358
ImGui::Spacing();
1359
ImGui::SeparatorText("One-liner variants");
1360
HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section.");
1361
1362
// Simplified one-liner Combo() API, using values packed in a single constant string
1363
// This is a convenience for when the selection set is small and known at compile-time.
1364
static int item_current_2 = 0;
1365
ImGui::Combo("combo 3 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1366
1367
// Simplified one-liner Combo() using an array of const char*
1368
// This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1369
static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1370
ImGui::Combo("combo 4 (array)", &item_current_3, items, IM_COUNTOF(items));
1371
1372
// Simplified one-liner Combo() using an accessor function
1373
static int item_current_4 = 0;
1374
ImGui::Combo("combo 5 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_COUNTOF(items));
1375
1376
ImGui::TreePop();
1377
}
1378
}
1379
1380
//-----------------------------------------------------------------------------
1381
// [SECTION] DemoWindowWidgetsDataTypes()
1382
//-----------------------------------------------------------------------------
1383
1384
static void DemoWindowWidgetsDataTypes()
1385
{
1386
IMGUI_DEMO_MARKER("Widgets/Data Types");
1387
if (ImGui::TreeNode("Data Types"))
1388
{
1389
// DragScalar/InputScalar/SliderScalar functions allow various data types
1390
// - signed/unsigned
1391
// - 8/16/32/64-bits
1392
// - integer/float/double
1393
// To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
1394
// to pass the type, and passing all arguments by pointer.
1395
// This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
1396
// In practice, if you frequently use a given type that is not covered by the normal API entry points,
1397
// you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
1398
// and then pass their address to the generic function. For example:
1399
// bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
1400
// {
1401
// return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
1402
// }
1403
1404
// Setup limits (as helper variables so we can take their address, as explained above)
1405
// Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
1406
#ifndef LLONG_MIN
1407
ImS64 LLONG_MIN = -9223372036854775807LL - 1;
1408
ImS64 LLONG_MAX = 9223372036854775807LL;
1409
ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
1410
#endif
1411
const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
1412
const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
1413
const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
1414
const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
1415
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;
1416
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;
1417
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;
1418
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;
1419
const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
1420
const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
1421
1422
// State
1423
static char s8_v = 127;
1424
static ImU8 u8_v = 255;
1425
static short s16_v = 32767;
1426
static ImU16 u16_v = 65535;
1427
static ImS32 s32_v = -1;
1428
static ImU32 u32_v = (ImU32)-1;
1429
static ImS64 s64_v = -1;
1430
static ImU64 u64_v = (ImU64)-1;
1431
static float f32_v = 0.123f;
1432
static double f64_v = 90000.01234567890123456789;
1433
1434
const float drag_speed = 0.2f;
1435
static bool drag_clamp = false;
1436
IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
1437
ImGui::SeparatorText("Drags");
1438
ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
1439
ImGui::SameLine(); HelpMarker(
1440
"As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
1441
"You can override the clamping limits by using Ctrl+Click to input a value.");
1442
ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
1443
ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
1444
ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
1445
ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
1446
ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
1447
ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
1448
ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
1449
ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
1450
ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
1451
ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
1452
ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
1453
ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
1454
ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
1455
1456
IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
1457
ImGui::SeparatorText("Sliders");
1458
ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
1459
ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
1460
ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
1461
ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
1462
ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
1463
ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
1464
ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
1465
ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X");
1466
ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
1467
ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
1468
ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
1469
ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
1470
ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
1471
ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64);
1472
ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
1473
ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
1474
ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms");
1475
ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
1476
ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
1477
ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
1478
ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
1479
ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
1480
ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
1481
1482
ImGui::SeparatorText("Sliders (reverse)");
1483
ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
1484
ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
1485
ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
1486
ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
1487
ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
1488
ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
1489
1490
IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
1491
static bool inputs_step = true;
1492
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
1493
ImGui::SeparatorText("Inputs");
1494
ImGui::Checkbox("Show step buttons", &inputs_step);
1495
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1496
ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal);
1497
ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal);
1498
ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags);
1499
ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags);
1500
ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags);
1501
ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags);
1502
ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags);
1503
ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags);
1504
ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags);
1505
ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags);
1506
ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags);
1507
ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags);
1508
ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags);
1509
ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags);
1510
1511
ImGui::TreePop();
1512
}
1513
}
1514
1515
//-----------------------------------------------------------------------------
1516
// [SECTION] DemoWindowWidgetsDisableBlocks()
1517
//-----------------------------------------------------------------------------
1518
1519
static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data)
1520
{
1521
IMGUI_DEMO_MARKER("Widgets/Disable Blocks");
1522
if (ImGui::TreeNode("Disable Blocks"))
1523
{
1524
ImGui::Checkbox("Disable entire section above", &demo_data->DisableSections);
1525
ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections.");
1526
ImGui::TreePop();
1527
}
1528
}
1529
1530
//-----------------------------------------------------------------------------
1531
// [SECTION] DemoWindowWidgetsDragAndDrop()
1532
//-----------------------------------------------------------------------------
1533
1534
static void DemoWindowWidgetsDragAndDrop()
1535
{
1536
IMGUI_DEMO_MARKER("Widgets/Drag and drop");
1537
if (ImGui::TreeNode("Drag and Drop"))
1538
{
1539
IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
1540
if (ImGui::TreeNode("Drag and drop in standard widgets"))
1541
{
1542
// ColorEdit widgets automatically act as drag source and drag target.
1543
// They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
1544
// to allow your own widgets to use colors in their drag and drop interaction.
1545
// Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
1546
HelpMarker("You can drag from the color squares.");
1547
static float col1[3] = { 1.0f, 0.0f, 0.2f };
1548
static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
1549
ImGui::ColorEdit3("color 1", col1);
1550
ImGui::ColorEdit4("color 2", col2);
1551
ImGui::TreePop();
1552
}
1553
1554
IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
1555
if (ImGui::TreeNode("Drag and drop to copy/swap items"))
1556
{
1557
enum Mode
1558
{
1559
Mode_Copy,
1560
Mode_Move,
1561
Mode_Swap
1562
};
1563
static int mode = 0;
1564
if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
1565
if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
1566
if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
1567
static const char* names[9] =
1568
{
1569
"Bobby", "Beatrice", "Betty",
1570
"Brianna", "Barry", "Bernard",
1571
"Bibi", "Blaine", "Bryn"
1572
};
1573
for (int n = 0; n < IM_COUNTOF(names); n++)
1574
{
1575
ImGui::PushID(n);
1576
if ((n % 3) != 0)
1577
ImGui::SameLine();
1578
ImGui::Button(names[n], ImVec2(60, 60));
1579
1580
// Our buttons are both drag sources and drag targets here!
1581
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
1582
{
1583
// Set payload to carry the index of our item (could be anything)
1584
ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
1585
1586
// Display preview (could be anything, e.g. when dragging an image we could decide to display
1587
// the filename and a small preview of the image, etc.)
1588
if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
1589
if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
1590
if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
1591
ImGui::EndDragDropSource();
1592
}
1593
if (ImGui::BeginDragDropTarget())
1594
{
1595
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
1596
{
1597
IM_ASSERT(payload->DataSize == sizeof(int));
1598
int payload_n = *(const int*)payload->Data;
1599
if (mode == Mode_Copy)
1600
{
1601
names[n] = names[payload_n];
1602
}
1603
if (mode == Mode_Move)
1604
{
1605
names[n] = names[payload_n];
1606
names[payload_n] = "";
1607
}
1608
if (mode == Mode_Swap)
1609
{
1610
const char* tmp = names[n];
1611
names[n] = names[payload_n];
1612
names[payload_n] = tmp;
1613
}
1614
}
1615
ImGui::EndDragDropTarget();
1616
}
1617
ImGui::PopID();
1618
}
1619
ImGui::TreePop();
1620
}
1621
1622
IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
1623
if (ImGui::TreeNode("Drag to reorder items (simple)"))
1624
{
1625
// FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
1626
// This code was always slightly faulty but in a way which was not easily noticeable.
1627
// Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
1628
ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
1629
1630
// Simple reordering
1631
HelpMarker(
1632
"We don't use the drag and drop api at all here! "
1633
"Instead we query when the item is held but not hovered, and order items accordingly.");
1634
static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
1635
for (int n = 0; n < IM_COUNTOF(item_names); n++)
1636
{
1637
const char* item = item_names[n];
1638
ImGui::Selectable(item);
1639
1640
if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
1641
{
1642
int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
1643
if (n_next >= 0 && n_next < IM_COUNTOF(item_names))
1644
{
1645
item_names[n] = item_names[n_next];
1646
item_names[n_next] = item;
1647
ImGui::ResetMouseDragDelta();
1648
}
1649
}
1650
}
1651
1652
ImGui::PopItemFlag();
1653
ImGui::TreePop();
1654
}
1655
1656
IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
1657
if (ImGui::TreeNode("Tooltip at target location"))
1658
{
1659
for (int n = 0; n < 2; n++)
1660
{
1661
// Drop targets
1662
ImGui::Button(n ? "drop here##1" : "drop here##0");
1663
if (ImGui::BeginDragDropTarget())
1664
{
1665
ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
1666
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags))
1667
{
1668
IM_UNUSED(payload);
1669
ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
1670
ImGui::SetTooltip("Cannot drop here!");
1671
}
1672
ImGui::EndDragDropTarget();
1673
}
1674
1675
// Drop source
1676
static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
1677
if (n == 0)
1678
ImGui::ColorButton("drag me", col4);
1679
1680
}
1681
ImGui::TreePop();
1682
}
1683
1684
ImGui::TreePop();
1685
}
1686
}
1687
1688
//-----------------------------------------------------------------------------
1689
// [SECTION] DemoWindowWidgetsDragsAndSliders()
1690
//-----------------------------------------------------------------------------
1691
1692
static void DemoWindowWidgetsDragsAndSliders()
1693
{
1694
IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
1695
if (ImGui::TreeNode("Drag/Slider Flags"))
1696
{
1697
// Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
1698
static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
1699
ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
1700
ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput);
1701
ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with Ctrl+Click. By default Ctrl+Click allows going out of bounds.");
1702
ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange);
1703
ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.");
1704
ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
1705
ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
1706
ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
1707
ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
1708
ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
1709
ImGui::SameLine(); HelpMarker("Disable Ctrl+Click or Enter key allowing to input text directly into the widget.");
1710
ImGui::CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", &flags, ImGuiSliderFlags_NoSpeedTweaks);
1711
ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic.");
1712
ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
1713
ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
1714
ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers);
1715
//ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkersG", &flags, 1 << ImGuiSliderFlags_ColorMarkersIndexShift_); // Not explicitly documented but possible.
1716
1717
// Drags
1718
static float drag_f = 0.5f;
1719
static float drag_f4[4];
1720
static int drag_i = 50;
1721
ImGui::Text("Underlying float value: %f", drag_f);
1722
ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
1723
ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
1724
ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
1725
ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
1726
//ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange
1727
//ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
1728
ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
1729
ImGui::DragFloat4("DragFloat4 (0 -> 1)", drag_f4, 0.005f, 0.0f, 1.0f, "%.3f", flags); // Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers.
1730
1731
// Sliders
1732
static float slider_f = 0.5f;
1733
static float slider_f4[4];
1734
static int slider_i = 50;
1735
const ImGuiSliderFlags flags_for_sliders = (flags & ~ImGuiSliderFlags_WrapAround);
1736
ImGui::Text("Underlying float value: %f", slider_f);
1737
ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
1738
ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
1739
ImGui::SliderFloat4("SliderFloat4 (0 -> 1)", slider_f4, 0.0f, 1.0f, "%.3f", flags); // Multi-component item, mostly here to document the effect of ImGuiSliderFlags_ColorMarkers.
1740
1741
ImGui::TreePop();
1742
}
1743
}
1744
1745
//-----------------------------------------------------------------------------
1746
// [SECTION] DemoWindowWidgetsFonts()
1747
//-----------------------------------------------------------------------------
1748
1749
// Forward declare ShowFontAtlas() which isn't worth putting in public API yet
1750
namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
1751
1752
static void DemoWindowWidgetsFonts()
1753
{
1754
IMGUI_DEMO_MARKER("Widgets/Fonts");
1755
if (ImGui::TreeNode("Fonts"))
1756
{
1757
ImFontAtlas* atlas = ImGui::GetIO().Fonts;
1758
ImGui::ShowFontAtlas(atlas);
1759
// FIXME-NEWATLAS: Provide a demo to add/create a procedural font?
1760
ImGui::TreePop();
1761
}
1762
}
1763
1764
//-----------------------------------------------------------------------------
1765
// [SECTION] DemoWindowWidgetsImages()
1766
//-----------------------------------------------------------------------------
1767
1768
static void DemoWindowWidgetsImages()
1769
{
1770
IMGUI_DEMO_MARKER("Widgets/Images");
1771
if (ImGui::TreeNode("Images"))
1772
{
1773
ImGuiIO& io = ImGui::GetIO();
1774
ImGui::TextWrapped(
1775
"Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1776
"Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1777
"Hover the texture for a zoomed view!");
1778
1779
// Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1780
// Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers.
1781
// If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1782
// of their respective source file to specify what they are using as texture identifier, for example:
1783
// - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer.
1784
// - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1785
// So with the DirectX11 backend, you call ImGui::Image() with a 'ID3D11ShaderResourceView*' cast to ImTextureID.
1786
// - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1787
// to ImGui::Image(), and gather width/height through your own functions, etc.
1788
// - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1789
// it will help you debug issues if you are confused about it.
1790
// - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1791
// - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1792
// - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1793
1794
// Grab the current texture identifier used by the font atlas.
1795
ImTextureRef my_tex_id = io.Fonts->TexRef;
1796
1797
// Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it.
1798
float my_tex_w = (float)io.Fonts->TexData->Width;
1799
float my_tex_h = (float)io.Fonts->TexData->Height;
1800
1801
{
1802
ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1803
ImVec2 pos = ImGui::GetCursorScreenPos();
1804
ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1805
ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1806
ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize));
1807
ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
1808
if (ImGui::BeginItemTooltip())
1809
{
1810
float region_sz = 32.0f;
1811
float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1812
float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1813
float zoom = 4.0f;
1814
if (region_x < 0.0f) { region_x = 0.0f; }
1815
else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1816
if (region_y < 0.0f) { region_y = 0.0f; }
1817
else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1818
ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
1819
ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1820
ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1821
ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1822
ImGui::ImageWithBg(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
1823
ImGui::EndTooltip();
1824
}
1825
ImGui::PopStyleVar();
1826
}
1827
1828
IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1829
ImGui::TextWrapped("And now some textured buttons..");
1830
static int pressed_count = 0;
1831
for (int i = 0; i < 8; i++)
1832
{
1833
// UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1834
// Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1835
// Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1836
ImGui::PushID(i);
1837
if (i > 0)
1838
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
1839
ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
1840
ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
1841
ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture
1842
ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
1843
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1844
if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
1845
pressed_count += 1;
1846
if (i > 0)
1847
ImGui::PopStyleVar();
1848
ImGui::PopID();
1849
ImGui::SameLine();
1850
}
1851
ImGui::NewLine();
1852
ImGui::Text("Pressed %d times.", pressed_count);
1853
ImGui::TreePop();
1854
}
1855
}
1856
1857
//-----------------------------------------------------------------------------
1858
// [SECTION] DemoWindowWidgetsListBoxes()
1859
//-----------------------------------------------------------------------------
1860
1861
static void DemoWindowWidgetsListBoxes()
1862
{
1863
IMGUI_DEMO_MARKER("Widgets/List Boxes");
1864
if (ImGui::TreeNode("List Boxes"))
1865
{
1866
// BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
1867
// using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
1868
// You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
1869
// to always be called (inconsistent with BeginListBox()/EndListBox()).
1870
1871
// Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1872
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1873
// stored in the object itself, etc.)
1874
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1875
static int item_selected_idx = 0; // Here we store our selected data as an index.
1876
1877
static bool item_highlight = false;
1878
int item_highlighted_idx = -1; // Here we store our highlighted data as an index.
1879
ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight);
1880
1881
if (ImGui::BeginListBox("listbox 1"))
1882
{
1883
for (int n = 0; n < IM_COUNTOF(items); n++)
1884
{
1885
const bool is_selected = (item_selected_idx == n);
1886
if (ImGui::Selectable(items[n], is_selected))
1887
item_selected_idx = n;
1888
1889
if (item_highlight && ImGui::IsItemHovered())
1890
item_highlighted_idx = n;
1891
1892
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1893
if (is_selected)
1894
ImGui::SetItemDefaultFocus();
1895
}
1896
ImGui::EndListBox();
1897
}
1898
ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
1899
1900
// Custom size: use all width, 5 items tall
1901
ImGui::Text("Full-width:");
1902
if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1903
{
1904
for (int n = 0; n < IM_COUNTOF(items); n++)
1905
{
1906
bool is_selected = (item_selected_idx == n);
1907
ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0;
1908
if (ImGui::Selectable(items[n], is_selected, flags))
1909
item_selected_idx = n;
1910
1911
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1912
if (is_selected)
1913
ImGui::SetItemDefaultFocus();
1914
}
1915
ImGui::EndListBox();
1916
}
1917
1918
ImGui::TreePop();
1919
}
1920
}
1921
1922
//-----------------------------------------------------------------------------
1923
// [SECTION] DemoWindowWidgetsMultiComponents()
1924
//-----------------------------------------------------------------------------
1925
1926
static void DemoWindowWidgetsMultiComponents()
1927
{
1928
IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
1929
if (ImGui::TreeNode("Multi-component Widgets"))
1930
{
1931
static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
1932
static int vec4i[4] = { 1, 5, 100, 255 };
1933
1934
ImGui::SeparatorText("2-wide");
1935
ImGui::InputFloat2("input float2", vec4f);
1936
ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
1937
ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
1938
ImGui::InputInt2("input int2", vec4i);
1939
ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
1940
ImGui::SliderInt2("slider int2", vec4i, 0, 255);
1941
1942
ImGui::SeparatorText("3-wide");
1943
ImGui::InputFloat3("input float3", vec4f);
1944
ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
1945
ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
1946
ImGui::InputInt3("input int3", vec4i);
1947
ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
1948
ImGui::SliderInt3("slider int3", vec4i, 0, 255);
1949
1950
ImGui::SeparatorText("4-wide");
1951
ImGui::InputFloat4("input float4", vec4f);
1952
ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
1953
ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
1954
ImGui::InputInt4("input int4", vec4i);
1955
ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
1956
ImGui::SliderInt4("slider int4", vec4i, 0, 255);
1957
1958
ImGui::SeparatorText("Ranges");
1959
static float begin = 10, end = 90;
1960
static int begin_i = 100, end_i = 1000;
1961
ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
1962
ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
1963
ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
1964
1965
ImGui::TreePop();
1966
}
1967
}
1968
1969
//-----------------------------------------------------------------------------
1970
// [SECTION] DemoWindowWidgetsPlotting()
1971
//-----------------------------------------------------------------------------
1972
1973
static void DemoWindowWidgetsPlotting()
1974
{
1975
// Plot/Graph widgets are not very good.
1976
// Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
1977
// (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
1978
IMGUI_DEMO_MARKER("Widgets/Plotting");
1979
if (ImGui::TreeNode("Plotting"))
1980
{
1981
ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
1982
ImGui::TextLinkOpenURL("https://github.com/epezent/implot");
1983
ImGui::Separator();
1984
1985
static bool animate = true;
1986
ImGui::Checkbox("Animate", &animate);
1987
1988
// Plot as lines and plot as histogram
1989
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1990
ImGui::PlotLines("Frame Times", arr, IM_COUNTOF(arr));
1991
ImGui::PlotHistogram("Histogram", arr, IM_COUNTOF(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
1992
//ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
1993
1994
// Fill an array of contiguous float values to plot
1995
// Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
1996
// and the sizeof() of your structure in the "stride" parameter.
1997
static float values[90] = {};
1998
static int values_offset = 0;
1999
static double refresh_time = 0.0;
2000
if (!animate || refresh_time == 0.0)
2001
refresh_time = ImGui::GetTime();
2002
while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
2003
{
2004
static float phase = 0.0f;
2005
values[values_offset] = cosf(phase);
2006
values_offset = (values_offset + 1) % IM_COUNTOF(values);
2007
phase += 0.10f * values_offset;
2008
refresh_time += 1.0f / 60.0f;
2009
}
2010
2011
// Plots can display overlay texts
2012
// (in this example, we will display an average value)
2013
{
2014
float average = 0.0f;
2015
for (int n = 0; n < IM_COUNTOF(values); n++)
2016
average += values[n];
2017
average /= (float)IM_COUNTOF(values);
2018
char overlay[32];
2019
sprintf(overlay, "avg %f", average);
2020
ImGui::PlotLines("Lines", values, IM_COUNTOF(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
2021
}
2022
2023
// Use functions to generate output
2024
// FIXME: This is actually VERY awkward because current plot API only pass in indices.
2025
// We probably want an API passing floats and user provide sample rate/count.
2026
struct Funcs
2027
{
2028
static float Sin(void*, int i) { return sinf(i * 0.1f); }
2029
static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
2030
};
2031
static int func_type = 0, display_count = 70;
2032
ImGui::SeparatorText("Functions");
2033
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2034
ImGui::Combo("func", &func_type, "Sin\0Saw\0");
2035
ImGui::SameLine();
2036
ImGui::SliderInt("Sample count", &display_count, 1, 400);
2037
float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
2038
ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2039
ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2040
2041
ImGui::TreePop();
2042
}
2043
}
2044
2045
//-----------------------------------------------------------------------------
2046
// [SECTION] DemoWindowWidgetsProgressBars()
2047
//-----------------------------------------------------------------------------
2048
2049
static void DemoWindowWidgetsProgressBars()
2050
{
2051
IMGUI_DEMO_MARKER("Widgets/Progress Bars");
2052
if (ImGui::TreeNode("Progress Bars"))
2053
{
2054
// Animate a simple progress bar
2055
static float progress_accum = 0.0f, progress_dir = 1.0f;
2056
progress_accum += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
2057
if (progress_accum >= +1.1f) { progress_accum = +1.1f; progress_dir *= -1.0f; }
2058
if (progress_accum <= -0.1f) { progress_accum = -0.1f; progress_dir *= -1.0f; }
2059
2060
const float progress = IM_CLAMP(progress_accum, 0.0f, 1.0f);
2061
2062
// Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
2063
// or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
2064
ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
2065
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2066
ImGui::Text("Progress Bar");
2067
2068
char buf[32];
2069
sprintf(buf, "%d/%d", (int)(progress * 1753), 1753);
2070
ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
2071
2072
// Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value.
2073
// Adjust the factor if you want to adjust the animation speed.
2074
ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching..");
2075
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2076
ImGui::Text("Indeterminate");
2077
2078
ImGui::TreePop();
2079
}
2080
}
2081
2082
//-----------------------------------------------------------------------------
2083
// [SECTION] DemoWindowWidgetsQueryingStatuses()
2084
//-----------------------------------------------------------------------------
2085
2086
static void DemoWindowWidgetsQueryingStatuses()
2087
{
2088
IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2089
if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)"))
2090
{
2091
// Select an item type
2092
const char* item_names[] =
2093
{
2094
"Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2095
"InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2096
};
2097
static int item_type = 4;
2098
static bool item_disabled = false;
2099
ImGui::Combo("Item Type", &item_type, item_names, IM_COUNTOF(item_names), IM_COUNTOF(item_names));
2100
ImGui::SameLine();
2101
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().");
2102
ImGui::Checkbox("Item Disabled", &item_disabled);
2103
2104
// Submit selected items so we can query their status in the code following it.
2105
bool ret = false;
2106
static bool b = false;
2107
static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2108
static char str[16] = {};
2109
if (item_disabled)
2110
ImGui::BeginDisabled(true);
2111
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
2112
if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
2113
if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater)
2114
if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
2115
if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
2116
if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_COUNTOF(str)); } // Testing input text (which handles tabbing)
2117
if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_COUNTOF(str)); } // Testing input text (which uses a child window)
2118
if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
2119
if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2120
if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2121
if (item_type == 10) { ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
2122
if (item_type == 11) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2123
if (item_type == 12) { ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
2124
if (item_type == 13) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2125
if (item_type == 14) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_COUNTOF(items)); }
2126
if (item_type == 15) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_COUNTOF(items), IM_COUNTOF(items)); }
2127
2128
bool hovered_delay_none = ImGui::IsItemHovered();
2129
bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary);
2130
bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
2131
bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
2132
bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2133
2134
// Display the values of IsItemHovered() and other common item state functions.
2135
// Note that the ImGuiHoveredFlags_XXX flags can be combined.
2136
// Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2137
// we query every state in a single call to avoid storing them and to simplify the code.
2138
ImGui::BulletText(
2139
"Return value = %d\n"
2140
"IsItemFocused() = %d\n"
2141
"IsItemHovered() = %d\n"
2142
"IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2143
"IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2144
"IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2145
"IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2146
"IsItemHovered(_AllowWhenDisabled) = %d\n"
2147
"IsItemHovered(_RectOnly) = %d\n"
2148
"IsItemActive() = %d\n"
2149
"IsItemEdited() = %d\n"
2150
"IsItemActivated() = %d\n"
2151
"IsItemDeactivated() = %d\n"
2152
"IsItemDeactivatedAfterEdit() = %d\n"
2153
"IsItemVisible() = %d\n"
2154
"IsItemClicked() = %d\n"
2155
"IsItemToggledOpen() = %d\n"
2156
"GetItemRectMin() = (%.1f, %.1f)\n"
2157
"GetItemRectMax() = (%.1f, %.1f)\n"
2158
"GetItemRectSize() = (%.1f, %.1f)",
2159
ret,
2160
ImGui::IsItemFocused(),
2161
ImGui::IsItemHovered(),
2162
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2163
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2164
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2165
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2166
ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled),
2167
ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2168
ImGui::IsItemActive(),
2169
ImGui::IsItemEdited(),
2170
ImGui::IsItemActivated(),
2171
ImGui::IsItemDeactivated(),
2172
ImGui::IsItemDeactivatedAfterEdit(),
2173
ImGui::IsItemVisible(),
2174
ImGui::IsItemClicked(),
2175
ImGui::IsItemToggledOpen(),
2176
ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2177
ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2178
ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2179
);
2180
ImGui::BulletText(
2181
"with Hovering Delay or Stationary test:\n"
2182
"IsItemHovered() = %d\n"
2183
"IsItemHovered(_Stationary) = %d\n"
2184
"IsItemHovered(_DelayShort) = %d\n"
2185
"IsItemHovered(_DelayNormal) = %d\n"
2186
"IsItemHovered(_Tooltip) = %d",
2187
hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2188
2189
if (item_disabled)
2190
ImGui::EndDisabled();
2191
2192
char buf[1] = "";
2193
ImGui::InputText("unused", buf, IM_COUNTOF(buf), ImGuiInputTextFlags_ReadOnly);
2194
ImGui::SameLine();
2195
HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2196
2197
ImGui::TreePop();
2198
}
2199
2200
IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2201
if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)"))
2202
{
2203
static bool embed_all_inside_a_child_window = false;
2204
ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
2205
if (embed_all_inside_a_child_window)
2206
ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders);
2207
2208
// Testing IsWindowFocused() function with its various flags.
2209
ImGui::BulletText(
2210
"IsWindowFocused() = %d\n"
2211
"IsWindowFocused(_ChildWindows) = %d\n"
2212
"IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2213
"IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2214
"IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2215
"IsWindowFocused(_RootWindow) = %d\n"
2216
"IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2217
"IsWindowFocused(_AnyWindow) = %d\n",
2218
ImGui::IsWindowFocused(),
2219
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2220
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2221
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2222
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2223
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2224
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2225
ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2226
2227
// Testing IsWindowHovered() function with its various flags.
2228
ImGui::BulletText(
2229
"IsWindowHovered() = %d\n"
2230
"IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2231
"IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2232
"IsWindowHovered(_ChildWindows) = %d\n"
2233
"IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2234
"IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2235
"IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2236
"IsWindowHovered(_RootWindow) = %d\n"
2237
"IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2238
"IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2239
"IsWindowHovered(_AnyWindow) = %d\n"
2240
"IsWindowHovered(_Stationary) = %d\n",
2241
ImGui::IsWindowHovered(),
2242
ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2243
ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2244
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2245
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2246
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2247
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2248
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2249
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2250
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2251
ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
2252
ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
2253
2254
ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders);
2255
ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2256
ImGui::EndChild();
2257
if (embed_all_inside_a_child_window)
2258
ImGui::EndChild();
2259
2260
// Calling IsItemHovered() after begin returns the hovered status of the title bar.
2261
// This is useful in particular if you want to create a context menu associated to the title bar of a window.
2262
static bool test_window = false;
2263
ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2264
if (test_window)
2265
{
2266
ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2267
if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2268
{
2269
if (ImGui::MenuItem("Close")) { test_window = false; }
2270
ImGui::EndPopup();
2271
}
2272
ImGui::Text(
2273
"IsItemHovered() after begin = %d (== is title bar hovered)\n"
2274
"IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2275
ImGui::IsItemHovered(), ImGui::IsItemActive());
2276
ImGui::End();
2277
}
2278
2279
ImGui::TreePop();
2280
}
2281
}
2282
2283
//-----------------------------------------------------------------------------
2284
// [SECTION] DemoWindowWidgetsSelectables()
2285
//-----------------------------------------------------------------------------
2286
2287
static void DemoWindowWidgetsSelectables()
2288
{
2289
IMGUI_DEMO_MARKER("Widgets/Selectables");
2290
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
2291
if (ImGui::TreeNode("Selectables"))
2292
{
2293
// Selectable() has 2 overloads:
2294
// - The one taking "bool selected" as a read-only selection information.
2295
// When Selectable() has been clicked it returns true and you can alter selection state accordingly.
2296
// - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
2297
// The earlier is more flexible, as in real application your selection may be stored in many different ways
2298
// and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
2299
IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
2300
if (ImGui::TreeNode("Basic"))
2301
{
2302
static bool selection[5] = { false, true, false, false };
2303
ImGui::Selectable("1. I am selectable", &selection[0]);
2304
ImGui::Selectable("2. I am selectable", &selection[1]);
2305
ImGui::Selectable("3. I am selectable", &selection[2]);
2306
if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
2307
if (ImGui::IsMouseDoubleClicked(0))
2308
selection[3] = !selection[3];
2309
ImGui::TreePop();
2310
}
2311
2312
IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
2313
if (ImGui::TreeNode("Rendering more items on the same line"))
2314
{
2315
// (1) Using SetNextItemAllowOverlap()
2316
// (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
2317
static bool selected[3] = { false, false, false };
2318
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
2319
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
2320
ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
2321
ImGui::TreePop();
2322
}
2323
2324
IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables");
2325
if (ImGui::TreeNode("In Tables"))
2326
{
2327
static bool selected[10] = {};
2328
2329
if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
2330
{
2331
for (int i = 0; i < 10; i++)
2332
{
2333
char label[32];
2334
sprintf(label, "Item %d", i);
2335
ImGui::TableNextColumn();
2336
ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
2337
}
2338
ImGui::EndTable();
2339
}
2340
ImGui::Spacing();
2341
if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
2342
{
2343
for (int i = 0; i < 10; i++)
2344
{
2345
char label[32];
2346
sprintf(label, "Item %d", i);
2347
ImGui::TableNextRow();
2348
ImGui::TableNextColumn();
2349
ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
2350
ImGui::TableNextColumn();
2351
ImGui::Text("Some other contents");
2352
ImGui::TableNextColumn();
2353
ImGui::Text("123456");
2354
}
2355
ImGui::EndTable();
2356
}
2357
ImGui::TreePop();
2358
}
2359
2360
IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
2361
if (ImGui::TreeNode("Grid"))
2362
{
2363
static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
2364
2365
// Add in a bit of silly fun...
2366
const float time = (float)ImGui::GetTime();
2367
const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
2368
if (winning_state)
2369
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
2370
2371
for (int y = 0; y < 4; y++)
2372
for (int x = 0; x < 4; x++)
2373
{
2374
if (x > 0)
2375
ImGui::SameLine();
2376
ImGui::PushID(y * 4 + x);
2377
if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
2378
{
2379
// Toggle clicked cell + toggle neighbors
2380
selected[y][x] ^= 1;
2381
if (x > 0) { selected[y][x - 1] ^= 1; }
2382
if (x < 3) { selected[y][x + 1] ^= 1; }
2383
if (y > 0) { selected[y - 1][x] ^= 1; }
2384
if (y < 3) { selected[y + 1][x] ^= 1; }
2385
}
2386
ImGui::PopID();
2387
}
2388
2389
if (winning_state)
2390
ImGui::PopStyleVar();
2391
ImGui::TreePop();
2392
}
2393
IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
2394
if (ImGui::TreeNode("Alignment"))
2395
{
2396
HelpMarker(
2397
"By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
2398
"basis using PushStyleVar(). You'll probably want to always keep your default situation to "
2399
"left-align otherwise it becomes difficult to layout multiple items on a same line");
2400
static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
2401
for (int y = 0; y < 3; y++)
2402
{
2403
for (int x = 0; x < 3; x++)
2404
{
2405
ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
2406
char name[32];
2407
sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
2408
if (x > 0) ImGui::SameLine();
2409
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
2410
ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
2411
ImGui::PopStyleVar();
2412
}
2413
}
2414
ImGui::TreePop();
2415
}
2416
ImGui::TreePop();
2417
}
2418
}
2419
2420
//-----------------------------------------------------------------------------
2421
// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect()
2422
//-----------------------------------------------------------------------------
2423
// Multi-selection demos
2424
// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select
2425
//-----------------------------------------------------------------------------
2426
2427
static const char* ExampleNames[] =
2428
{
2429
"Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
2430
"Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
2431
"Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
2432
};
2433
2434
// Extra functions to add deletion support to ImGuiSelectionBasicStorage
2435
struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
2436
{
2437
// Find which item should be Focused after deletion.
2438
// Call _before_ item submission. Return an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
2439
// The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
2440
// - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
2441
// - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
2442
// - 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.
2443
// FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
2444
int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
2445
{
2446
if (Size == 0)
2447
return -1;
2448
2449
// If focused item is not selected...
2450
const int focused_idx = (int)ms_io->NavIdItem; // Index of currently focused item
2451
if (ms_io->NavIdSelected == false) // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx))
2452
{
2453
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.
2454
return focused_idx; // Request to focus same item after deletion.
2455
}
2456
2457
// If focused item is selected: land on first unselected item after focused item.
2458
for (int idx = focused_idx + 1; idx < items_count; idx++)
2459
if (!Contains(GetStorageIdFromIndex(idx)))
2460
return idx;
2461
2462
// If focused item is selected: otherwise return last unselected item before focused item.
2463
for (int idx = IM_MIN(focused_idx, items_count) - 1; idx >= 0; idx--)
2464
if (!Contains(GetStorageIdFromIndex(idx)))
2465
return idx;
2466
2467
return -1;
2468
}
2469
2470
// Rewrite item list (delete items) + update selection.
2471
// - Call after EndMultiSelect()
2472
// - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
2473
template<typename ITEM_TYPE>
2474
void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items, int item_curr_idx_to_select)
2475
{
2476
// Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
2477
// If NavId was not part of selection, we will stay on same item.
2478
ImVector<ITEM_TYPE> new_items;
2479
new_items.reserve(items.Size - Size);
2480
int item_next_idx_to_select = -1;
2481
for (int idx = 0; idx < items.Size; idx++)
2482
{
2483
if (!Contains(GetStorageIdFromIndex(idx)))
2484
new_items.push_back(items[idx]);
2485
if (item_curr_idx_to_select == idx)
2486
item_next_idx_to_select = new_items.Size - 1;
2487
}
2488
items.swap(new_items);
2489
2490
// Update selection
2491
Clear();
2492
if (item_next_idx_to_select != -1 && ms_io->NavIdSelected)
2493
SetItemSelected(GetStorageIdFromIndex(item_next_idx_to_select), true);
2494
}
2495
};
2496
2497
// Example: Implement dual list box storage and interface
2498
struct ExampleDualListBox
2499
{
2500
ImVector<ImGuiID> Items[2]; // ID is index into ExampleName[]
2501
ImGuiSelectionBasicStorage Selections[2]; // Store ExampleItemId into selection
2502
bool OptKeepSorted = true;
2503
2504
void MoveAll(int src, int dst)
2505
{
2506
IM_ASSERT((src == 0 && dst == 1) || (src == 1 && dst == 0));
2507
for (ImGuiID item_id : Items[src])
2508
Items[dst].push_back(item_id);
2509
Items[src].clear();
2510
SortItems(dst);
2511
Selections[src].Swap(Selections[dst]);
2512
Selections[src].Clear();
2513
}
2514
void MoveSelected(int src, int dst)
2515
{
2516
for (int src_n = 0; src_n < Items[src].Size; src_n++)
2517
{
2518
ImGuiID item_id = Items[src][src_n];
2519
if (!Selections[src].Contains(item_id))
2520
continue;
2521
Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap)
2522
Items[dst].push_back(item_id);
2523
src_n--;
2524
}
2525
if (OptKeepSorted)
2526
SortItems(dst);
2527
Selections[src].Swap(Selections[dst]);
2528
Selections[src].Clear();
2529
}
2530
void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side)
2531
{
2532
// In this example we store item id in selection (instead of item index)
2533
Selections[side].UserData = Items[side].Data;
2534
Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
2535
Selections[side].ApplyRequests(ms_io);
2536
}
2537
static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
2538
{
2539
const int* a = (const int*)lhs;
2540
const int* b = (const int*)rhs;
2541
return *a - *b;
2542
}
2543
void SortItems(int n)
2544
{
2545
qsort(Items[n].Data, (size_t)Items[n].Size, sizeof(Items[n][0]), CompareItemsByValue);
2546
}
2547
void Show()
2548
{
2549
//if (ImGui::Checkbox("Sorted", &OptKeepSorted) && OptKeepSorted) { SortItems(0); SortItems(1); }
2550
if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None))
2551
{
2552
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side
2553
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); // Buttons
2554
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Right side
2555
ImGui::TableNextRow();
2556
2557
int request_move_selected = -1;
2558
int request_move_all = -1;
2559
float child_height_0 = 0.0f;
2560
for (int side = 0; side < 2; side++)
2561
{
2562
// FIXME-MULTISELECT: Dual List Box: Add context menus
2563
// FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues.
2564
ImVector<ImGuiID>& items = Items[side];
2565
ImGuiSelectionBasicStorage& selection = Selections[side];
2566
2567
ImGui::TableSetColumnIndex((side == 0) ? 0 : 2);
2568
ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size);
2569
2570
// Submit scrolling range to avoid glitches on moving/deletion
2571
const float items_height = ImGui::GetTextLineHeightWithSpacing();
2572
ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
2573
2574
bool child_visible;
2575
if (side == 0)
2576
{
2577
// Left child is resizable
2578
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX));
2579
child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY);
2580
child_height_0 = ImGui::GetWindowSize().y;
2581
}
2582
else
2583
{
2584
// Right child use same height as left one
2585
child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle);
2586
}
2587
if (child_visible)
2588
{
2589
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
2590
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
2591
ApplySelectionRequests(ms_io, side);
2592
2593
for (int item_n = 0; item_n < items.Size; item_n++)
2594
{
2595
ImGuiID item_id = items[item_n];
2596
bool item_is_selected = selection.Contains(item_id);
2597
ImGui::SetNextItemSelectionUserData(item_n);
2598
ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick);
2599
if (ImGui::IsItemFocused())
2600
{
2601
// FIXME-MULTISELECT: Dual List Box: Transfer focus
2602
if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
2603
request_move_selected = side;
2604
if (ImGui::IsMouseDoubleClicked(0)) // FIXME-MULTISELECT: Double-click on multi-selection?
2605
request_move_selected = side;
2606
}
2607
}
2608
2609
ms_io = ImGui::EndMultiSelect();
2610
ApplySelectionRequests(ms_io, side);
2611
}
2612
ImGui::EndChild();
2613
}
2614
2615
// Buttons columns
2616
ImGui::TableSetColumnIndex(1);
2617
ImGui::NewLine();
2618
//ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f };
2619
ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() };
2620
2621
// (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized)
2622
if (ImGui::Button(">>", button_sz))
2623
request_move_all = 0;
2624
if (ImGui::Button(">", button_sz))
2625
request_move_selected = 0;
2626
if (ImGui::Button("<", button_sz))
2627
request_move_selected = 1;
2628
if (ImGui::Button("<<", button_sz))
2629
request_move_all = 1;
2630
2631
// Process requests
2632
if (request_move_all != -1)
2633
MoveAll(request_move_all, request_move_all ^ 1);
2634
if (request_move_selected != -1)
2635
MoveSelected(request_move_selected, request_move_selected ^ 1);
2636
2637
// FIXME-MULTISELECT: Support action from outside
2638
/*
2639
if (OptKeepSorted == false)
2640
{
2641
ImGui::NewLine();
2642
if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {}
2643
if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {}
2644
}
2645
*/
2646
2647
ImGui::EndTable();
2648
}
2649
}
2650
};
2651
2652
static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data)
2653
{
2654
IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select");
2655
if (ImGui::TreeNode("Selection State & Multi-Select"))
2656
{
2657
HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
2658
2659
ImGui::BulletText("Wiki page:");
2660
ImGui::SameLine();
2661
ImGui::TextLinkOpenURL("imgui/wiki/Multi-Select", "https://github.com/ocornut/imgui/wiki/Multi-Select");
2662
2663
// Without any fancy API: manage single-selection yourself.
2664
IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select");
2665
if (ImGui::TreeNode("Single-Select"))
2666
{
2667
static int selected = -1;
2668
for (int n = 0; n < 5; n++)
2669
{
2670
char buf[32];
2671
sprintf(buf, "Object %d", n);
2672
if (ImGui::Selectable(buf, selected == n))
2673
selected = n;
2674
}
2675
ImGui::TreePop();
2676
}
2677
2678
// Demonstrate implementation a most-basic form of multi-selection manually
2679
// This doesn't support the Shift modifier which requires BeginMultiSelect()!
2680
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)");
2681
if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)"))
2682
{
2683
HelpMarker("Hold Ctrl and Click to select multiple items.");
2684
static bool selection[5] = { false, false, false, false, false };
2685
for (int n = 0; n < 5; n++)
2686
{
2687
char buf[32];
2688
sprintf(buf, "Object %d", n);
2689
if (ImGui::Selectable(buf, selection[n]))
2690
{
2691
if (!ImGui::GetIO().KeyCtrl) // Clear selection when Ctrl is not held
2692
memset(selection, 0, sizeof(selection));
2693
selection[n] ^= 1; // Toggle current item
2694
}
2695
}
2696
ImGui::TreePop();
2697
}
2698
2699
// Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API.
2700
// Shift+Click w/ Ctrl and other standard features are supported.
2701
// We use the ImGuiSelectionBasicStorage helper which you may freely reimplement.
2702
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select");
2703
if (ImGui::TreeNode("Multi-Select"))
2704
{
2705
ImGui::Text("Supported features:");
2706
ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space).");
2707
ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
2708
ImGui::BulletText("Shift modifier for range selection.");
2709
ImGui::BulletText("Ctrl+A to select all.");
2710
ImGui::BulletText("Escape to clear selection.");
2711
ImGui::BulletText("Click and drag to box-select.");
2712
ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
2713
2714
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
2715
const int ITEMS_COUNT = 50;
2716
static ImGuiSelectionBasicStorage selection;
2717
ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
2718
2719
// The BeginChild() has no purpose for selection logic, other that offering a scrolling region.
2720
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
2721
{
2722
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
2723
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
2724
selection.ApplyRequests(ms_io);
2725
2726
for (int n = 0; n < ITEMS_COUNT; n++)
2727
{
2728
char label[64];
2729
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
2730
bool item_is_selected = selection.Contains((ImGuiID)n);
2731
ImGui::SetNextItemSelectionUserData(n);
2732
ImGui::Selectable(label, item_is_selected);
2733
}
2734
2735
ms_io = ImGui::EndMultiSelect();
2736
selection.ApplyRequests(ms_io);
2737
}
2738
ImGui::EndChild();
2739
ImGui::TreePop();
2740
}
2741
2742
// Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
2743
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
2744
if (ImGui::TreeNode("Multi-Select (with clipper)"))
2745
{
2746
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
2747
static ImGuiSelectionBasicStorage selection;
2748
2749
ImGui::Text("Added features:");
2750
ImGui::BulletText("Using ImGuiListClipper.");
2751
2752
const int ITEMS_COUNT = 10000;
2753
ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
2754
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
2755
{
2756
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
2757
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
2758
selection.ApplyRequests(ms_io);
2759
2760
ImGuiListClipper clipper;
2761
clipper.Begin(ITEMS_COUNT);
2762
if (ms_io->RangeSrcItem != -1)
2763
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
2764
while (clipper.Step())
2765
{
2766
for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
2767
{
2768
char label[64];
2769
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
2770
bool item_is_selected = selection.Contains((ImGuiID)n);
2771
ImGui::SetNextItemSelectionUserData(n);
2772
ImGui::Selectable(label, item_is_selected);
2773
}
2774
}
2775
2776
ms_io = ImGui::EndMultiSelect();
2777
selection.ApplyRequests(ms_io);
2778
}
2779
ImGui::EndChild();
2780
ImGui::TreePop();
2781
}
2782
2783
// Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API.
2784
// In order to support Deletion without any glitches you need to:
2785
// - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling.
2786
// - (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.
2787
// - (3) BeginXXXX process
2788
// - (4) Focus process
2789
// - (5) EndXXXX process
2790
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
2791
if (ImGui::TreeNode("Multi-Select (with deletion)"))
2792
{
2793
// Storing items data separately from selection data.
2794
// (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
2795
// Use a custom selection.Adapter: store item identifier in Selection (instead of index)
2796
static ImVector<ImGuiID> items;
2797
static ExampleSelectionWithDeletion selection;
2798
selection.UserData = (void*)&items;
2799
selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->UserData; return (*p_items)[idx]; }; // Index -> ID
2800
2801
ImGui::Text("Added features:");
2802
ImGui::BulletText("Dynamic list with Delete key support.");
2803
ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
2804
2805
// Initialize default list with 50 items + button to add/remove items.
2806
static ImGuiID items_next_id = 0;
2807
if (items_next_id == 0)
2808
for (ImGuiID n = 0; n < 50; n++)
2809
items.push_back(items_next_id++);
2810
if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
2811
ImGui::SameLine();
2812
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(); } }
2813
2814
// (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
2815
const float items_height = ImGui::GetTextLineHeightWithSpacing();
2816
ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
2817
2818
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
2819
{
2820
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
2821
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
2822
selection.ApplyRequests(ms_io);
2823
2824
const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
2825
const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
2826
2827
for (int n = 0; n < items.Size; n++)
2828
{
2829
const ImGuiID item_id = items[n];
2830
char label[64];
2831
sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_COUNTOF(ExampleNames)]);
2832
2833
bool item_is_selected = selection.Contains(item_id);
2834
ImGui::SetNextItemSelectionUserData(n);
2835
ImGui::Selectable(label, item_is_selected);
2836
if (item_curr_idx_to_focus == n)
2837
ImGui::SetKeyboardFocusHere(-1);
2838
}
2839
2840
// Apply multi-select requests
2841
ms_io = ImGui::EndMultiSelect();
2842
selection.ApplyRequests(ms_io);
2843
if (want_delete)
2844
selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
2845
}
2846
ImGui::EndChild();
2847
ImGui::TreePop();
2848
}
2849
2850
// Implement a Dual List Box (#6648)
2851
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)");
2852
if (ImGui::TreeNode("Multi-Select (dual list box)"))
2853
{
2854
// Init default state
2855
static ExampleDualListBox dlb;
2856
if (dlb.Items[0].Size == 0 && dlb.Items[1].Size == 0)
2857
for (int item_id = 0; item_id < IM_COUNTOF(ExampleNames); item_id++)
2858
dlb.Items[0].push_back((ImGuiID)item_id);
2859
2860
// Show
2861
dlb.Show();
2862
2863
ImGui::TreePop();
2864
}
2865
2866
// Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
2867
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)");
2868
if (ImGui::TreeNode("Multi-Select (in a table)"))
2869
{
2870
static ImGuiSelectionBasicStorage selection;
2871
2872
const int ITEMS_COUNT = 10000;
2873
ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
2874
if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter, ImVec2(0.0f, ImGui::GetFontSize() * 20)))
2875
{
2876
ImGui::TableSetupColumn("Object");
2877
ImGui::TableSetupColumn("Action");
2878
ImGui::TableSetupScrollFreeze(0, 1);
2879
ImGui::TableHeadersRow();
2880
2881
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
2882
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
2883
selection.ApplyRequests(ms_io);
2884
2885
ImGuiListClipper clipper;
2886
clipper.Begin(ITEMS_COUNT);
2887
if (ms_io->RangeSrcItem != -1)
2888
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
2889
while (clipper.Step())
2890
{
2891
for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
2892
{
2893
ImGui::TableNextRow();
2894
ImGui::TableNextColumn();
2895
ImGui::PushID(n);
2896
char label[64];
2897
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
2898
bool item_is_selected = selection.Contains((ImGuiID)n);
2899
ImGui::SetNextItemSelectionUserData(n);
2900
ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
2901
ImGui::TableNextColumn();
2902
ImGui::SmallButton("hello");
2903
ImGui::PopID();
2904
}
2905
}
2906
2907
ms_io = ImGui::EndMultiSelect();
2908
selection.ApplyRequests(ms_io);
2909
ImGui::EndTable();
2910
}
2911
ImGui::TreePop();
2912
}
2913
2914
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)");
2915
if (ImGui::TreeNode("Multi-Select (checkboxes)"))
2916
{
2917
ImGui::Text("In a list of checkboxes (not selectable):");
2918
ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags.");
2919
ImGui::BulletText("Shift+Click to check multiple boxes.");
2920
ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
2921
2922
// If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
2923
static bool items[20] = {};
2924
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
2925
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
2926
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
2927
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
2928
2929
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
2930
{
2931
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_COUNTOF(items));
2932
ImGuiSelectionExternalStorage storage_wrapper;
2933
storage_wrapper.UserData = (void*)items;
2934
storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
2935
storage_wrapper.ApplyRequests(ms_io);
2936
for (int n = 0; n < 20; n++)
2937
{
2938
char label[32];
2939
sprintf(label, "Item %d", n);
2940
ImGui::SetNextItemSelectionUserData(n);
2941
ImGui::Checkbox(label, &items[n]);
2942
}
2943
ms_io = ImGui::EndMultiSelect();
2944
storage_wrapper.ApplyRequests(ms_io);
2945
}
2946
ImGui::EndChild();
2947
2948
ImGui::TreePop();
2949
}
2950
2951
// Demonstrate individual selection scopes in same window
2952
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)");
2953
if (ImGui::TreeNode("Multi-Select (multiple scopes)"))
2954
{
2955
// Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
2956
const int SCOPES_COUNT = 3;
2957
const int ITEMS_COUNT = 8; // Per scope
2958
static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT];
2959
2960
// Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
2961
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid;
2962
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
2963
flags &= ~ImGuiMultiSelectFlags_ScopeRect;
2964
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
2965
flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
2966
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
2967
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
2968
2969
for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++)
2970
{
2971
ImGui::PushID(selection_scope_n);
2972
ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
2973
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
2974
selection->ApplyRequests(ms_io);
2975
2976
ImGui::SeparatorText("Selection scope");
2977
ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
2978
2979
for (int n = 0; n < ITEMS_COUNT; n++)
2980
{
2981
char label[64];
2982
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_COUNTOF(ExampleNames)]);
2983
bool item_is_selected = selection->Contains((ImGuiID)n);
2984
ImGui::SetNextItemSelectionUserData(n);
2985
ImGui::Selectable(label, item_is_selected);
2986
}
2987
2988
// Apply multi-select requests
2989
ms_io = ImGui::EndMultiSelect();
2990
selection->ApplyRequests(ms_io);
2991
ImGui::PopID();
2992
}
2993
ImGui::TreePop();
2994
}
2995
2996
// See ShowExampleAppAssetsBrowser()
2997
if (ImGui::TreeNode("Multi-Select (tiled assets browser)"))
2998
{
2999
ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser);
3000
ImGui::Text("(also access from 'Examples->Assets Browser' in menu)");
3001
ImGui::TreePop();
3002
}
3003
3004
// Demonstrate supporting multiple-selection in a tree.
3005
// - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly!
3006
// This showcase how SetNextItemSelectionUserData() never assume indices!
3007
// - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request.
3008
// We want this interpolation to match what the user sees: in visible order, skipping closed nodes.
3009
// This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper.
3010
// - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you
3011
// are more likely to build an array mapping sequential indices to visible tree nodes, since your
3012
// filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier.
3013
// - Consider this a prototype: we are working toward simplifying some of it.
3014
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)");
3015
if (ImGui::TreeNode("Multi-Select (trees)"))
3016
{
3017
HelpMarker(
3018
"This is rather advanced and experimental. If you are getting started with multi-select, "
3019
"please don't start by looking at how to use it for a tree!\n\n"
3020
"Future versions will try to simplify and formalize some of this.");
3021
3022
struct ExampleTreeFuncs
3023
{
3024
static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection)
3025
{
3026
ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3027
tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Enable pressing left to jump to parent
3028
if (node->Childs.Size == 0)
3029
tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf;
3030
if (selection->Contains((ImGuiID)node->UID))
3031
tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3032
3033
// Using SetNextItemStorageID() to specify storage id, so we can easily peek into
3034
// the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions.
3035
ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node);
3036
ImGui::SetNextItemStorageID((ImGuiID)node->UID);
3037
if (ImGui::TreeNodeEx(node->Name, tree_node_flags))
3038
{
3039
for (ExampleTreeNode* child : node->Childs)
3040
DrawNode(child, selection);
3041
ImGui::TreePop();
3042
}
3043
else if (ImGui::IsItemToggledOpen())
3044
{
3045
TreeCloseAndUnselectChildNodes(node, selection);
3046
}
3047
}
3048
3049
static bool TreeNodeGetOpen(ExampleTreeNode* node)
3050
{
3051
return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID);
3052
}
3053
3054
static void TreeNodeSetOpen(ExampleTreeNode* node, bool open)
3055
{
3056
ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open);
3057
}
3058
3059
// When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected.
3060
// FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node
3061
// features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc.
3062
static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0)
3063
{
3064
// Recursive close (the test for depth == 0 is because we call this on a node that was just closed!)
3065
int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0;
3066
if (depth == 0 || TreeNodeGetOpen(node))
3067
{
3068
for (ExampleTreeNode* child : node->Childs)
3069
unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1);
3070
TreeNodeSetOpen(node, false);
3071
}
3072
3073
// Select root node if any of its child was selected, otherwise unselect
3074
selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0));
3075
return unselected_count;
3076
}
3077
3078
// Apply multi-selection requests
3079
static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection)
3080
{
3081
for (ImGuiSelectionRequest& req : ms_io->Requests)
3082
{
3083
if (req.Type == ImGuiSelectionRequestType_SetAll)
3084
{
3085
if (req.Selected)
3086
TreeSetAllInOpenNodes(tree, selection, req.Selected);
3087
else
3088
selection->Clear();
3089
}
3090
else if (req.Type == ImGuiSelectionRequestType_SetRange)
3091
{
3092
ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem;
3093
ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem;
3094
for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node))
3095
selection->SetItemSelected((ImGuiID)node->UID, req.Selected);
3096
}
3097
}
3098
}
3099
3100
static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected)
3101
{
3102
if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme
3103
selection->SetItemSelected((ImGuiID)node->UID, selected);
3104
if (node->Parent == NULL || TreeNodeGetOpen(node))
3105
for (ExampleTreeNode* child : node->Childs)
3106
TreeSetAllInOpenNodes(child, selection, selected);
3107
}
3108
3109
// Interpolate in *user-visible order* AND only *over opened nodes*.
3110
// If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler.
3111
// Here the tricks are that:
3112
// - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion.
3113
// this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)'
3114
// which would only be called when crossing from child to a parent, aka not too much.
3115
// - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack,
3116
// making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location.
3117
static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node)
3118
{
3119
// Reached last node
3120
if (curr_node == last_node)
3121
return NULL;
3122
3123
// Recurse into childs. Query storage to tell if the node is open.
3124
if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node))
3125
return curr_node->Childs[0];
3126
3127
// Next sibling, then into our own parent
3128
while (curr_node->Parent != NULL)
3129
{
3130
if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size)
3131
return curr_node->Parent->Childs[curr_node->IndexInParent + 1];
3132
curr_node = curr_node->Parent;
3133
}
3134
return NULL;
3135
}
3136
3137
}; // ExampleTreeFuncs
3138
3139
static ImGuiSelectionBasicStorage selection;
3140
if (demo_data->DemoTree == NULL)
3141
demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once
3142
ImGui::Text("Selection size: %d", selection.Size);
3143
3144
if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3145
{
3146
ExampleTreeNode* tree = demo_data->DemoTree;
3147
ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d;
3148
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1);
3149
ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3150
for (ExampleTreeNode* node : tree->Childs)
3151
ExampleTreeFuncs::DrawNode(node, &selection);
3152
ms_io = ImGui::EndMultiSelect();
3153
ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3154
}
3155
ImGui::EndChild();
3156
3157
ImGui::TreePop();
3158
}
3159
3160
// Advanced demonstration of BeginMultiSelect()
3161
// - Showcase clipping.
3162
// - Showcase deletion.
3163
// - Showcase basic drag and drop.
3164
// - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
3165
// - Showcase using inside a table.
3166
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)");
3167
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
3168
if (ImGui::TreeNode("Multi-Select (advanced)"))
3169
{
3170
// Options
3171
enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
3172
static bool use_clipper = true;
3173
static bool use_deletion = true;
3174
static bool use_drag_drop = true;
3175
static bool show_in_table = false;
3176
static bool show_color_button = true;
3177
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3178
static WidgetType widget_type = WidgetType_Selectable;
3179
3180
if (ImGui::TreeNode("Options"))
3181
{
3182
if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
3183
ImGui::SameLine();
3184
if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
3185
ImGui::SameLine();
3186
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.");
3187
ImGui::Checkbox("Enable clipper", &use_clipper);
3188
ImGui::Checkbox("Enable deletion", &use_deletion);
3189
ImGui::Checkbox("Enable drag & drop", &use_drag_drop);
3190
ImGui::Checkbox("Show in a table", &show_in_table);
3191
ImGui::Checkbox("Show color button", &show_color_button);
3192
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect);
3193
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
3194
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect);
3195
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3196
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3197
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect);
3198
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectOnRightClick", &flags, ImGuiMultiSelectFlags_NoSelectOnRightClick);
3199
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3200
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d);
3201
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll);
3202
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
3203
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3204
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3205
flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3206
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3207
flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3208
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick))
3209
flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease;
3210
if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
3211
flags &= ~ImGuiMultiSelectFlags_SelectOnClick;
3212
ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
3213
ImGui::TreePop();
3214
}
3215
3216
// Initialize default list with 1000 items.
3217
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3218
static ImVector<int> items;
3219
static int items_next_id = 0;
3220
if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
3221
static ExampleSelectionWithDeletion selection;
3222
static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
3223
3224
ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3225
3226
const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
3227
ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3228
if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3229
{
3230
ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
3231
if (widget_type == WidgetType_TreeNode)
3232
ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3233
3234
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3235
selection.ApplyRequests(ms_io);
3236
3237
const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
3238
const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3239
request_deletion_from_menu = false;
3240
3241
if (show_in_table)
3242
{
3243
if (widget_type == WidgetType_TreeNode)
3244
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
3245
ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX);
3246
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f);
3247
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f);
3248
//ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3249
}
3250
3251
ImGuiListClipper clipper;
3252
if (use_clipper)
3253
{
3254
clipper.Begin(items.Size);
3255
if (item_curr_idx_to_focus != -1)
3256
clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
3257
if (ms_io->RangeSrcItem != -1)
3258
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3259
}
3260
3261
while (!use_clipper || clipper.Step())
3262
{
3263
const int item_begin = use_clipper ? clipper.DisplayStart : 0;
3264
const int item_end = use_clipper ? clipper.DisplayEnd : items.Size;
3265
for (int n = item_begin; n < item_end; n++)
3266
{
3267
if (show_in_table)
3268
ImGui::TableNextColumn();
3269
3270
const int item_id = items[n];
3271
const char* item_category = ExampleNames[item_id % IM_COUNTOF(ExampleNames)];
3272
char label[64];
3273
sprintf(label, "Object %05d: %s", item_id, item_category);
3274
3275
// IMPORTANT: for deletion refocus to work we need object ID to be stable,
3276
// aka not depend on their index in the list. Here we use our persistent item_id
3277
// instead of index to build a unique ID that will persist.
3278
// (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
3279
ImGui::PushID(item_id);
3280
3281
// Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
3282
// of the selection scope doesn't erroneously alter our selection.
3283
if (show_color_button)
3284
{
3285
ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
3286
ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz);
3287
ImGui::SameLine();
3288
}
3289
3290
// Submit item
3291
bool item_is_selected = selection.Contains((ImGuiID)n);
3292
bool item_is_open = false;
3293
ImGui::SetNextItemSelectionUserData(n);
3294
if (widget_type == WidgetType_Selectable)
3295
{
3296
ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
3297
}
3298
else if (widget_type == WidgetType_TreeNode)
3299
{
3300
ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3301
if (item_is_selected)
3302
tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3303
item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
3304
}
3305
3306
// Focus (for after deletion)
3307
if (item_curr_idx_to_focus == n)
3308
ImGui::SetKeyboardFocusHere(-1);
3309
3310
// Drag and Drop
3311
if (use_drag_drop && ImGui::BeginDragDropSource())
3312
{
3313
// Create payload with full selection OR single unselected item.
3314
// (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
3315
if (ImGui::GetDragDropPayload() == NULL)
3316
{
3317
ImVector<int> payload_items;
3318
void* it = NULL;
3319
ImGuiID id = 0;
3320
if (!item_is_selected)
3321
payload_items.push_back(item_id);
3322
else
3323
while (selection.GetNextSelectedItem(&it, &id))
3324
payload_items.push_back((int)id);
3325
ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
3326
}
3327
3328
// Display payload content in tooltip
3329
const ImGuiPayload* payload = ImGui::GetDragDropPayload();
3330
const int* payload_items = (int*)payload->Data;
3331
const int payload_count = (int)payload->DataSize / (int)sizeof(int);
3332
if (payload_count == 1)
3333
ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_COUNTOF(ExampleNames)]);
3334
else
3335
ImGui::Text("Dragging %d objects", payload_count);
3336
3337
ImGui::EndDragDropSource();
3338
}
3339
3340
if (widget_type == WidgetType_TreeNode && item_is_open)
3341
ImGui::TreePop();
3342
3343
// Right-click: context menu
3344
if (ImGui::BeginPopupContextItem())
3345
{
3346
ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
3347
sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
3348
if (ImGui::Selectable(label))
3349
request_deletion_from_menu = true;
3350
ImGui::EndDisabled();
3351
ImGui::Selectable("Close");
3352
ImGui::EndPopup();
3353
}
3354
3355
// Demo content within a table
3356
if (show_in_table)
3357
{
3358
ImGui::TableNextColumn();
3359
ImGui::SetNextItemWidth(-FLT_MIN);
3360
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3361
ImGui::InputText("##NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly);
3362
ImGui::PopStyleVar();
3363
}
3364
3365
ImGui::PopID();
3366
}
3367
if (!use_clipper)
3368
break;
3369
}
3370
3371
if (show_in_table)
3372
{
3373
ImGui::EndTable();
3374
if (widget_type == WidgetType_TreeNode)
3375
ImGui::PopStyleVar();
3376
}
3377
3378
// Apply multi-select requests
3379
ms_io = ImGui::EndMultiSelect();
3380
selection.ApplyRequests(ms_io);
3381
if (want_delete)
3382
selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3383
3384
if (widget_type == WidgetType_TreeNode)
3385
ImGui::PopStyleVar();
3386
}
3387
ImGui::EndChild();
3388
ImGui::TreePop();
3389
}
3390
ImGui::TreePop();
3391
}
3392
}
3393
3394
//-----------------------------------------------------------------------------
3395
// [SECTION] DemoWindowWidgetsTabs()
3396
//-----------------------------------------------------------------------------
3397
3398
static void EditTabBarFittingPolicyFlags(ImGuiTabBarFlags* p_flags)
3399
{
3400
if ((*p_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
3401
*p_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
3402
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyMixed", p_flags, ImGuiTabBarFlags_FittingPolicyMixed))
3403
*p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyMixed);
3404
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyShrink", p_flags, ImGuiTabBarFlags_FittingPolicyShrink))
3405
*p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyShrink);
3406
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", p_flags, ImGuiTabBarFlags_FittingPolicyScroll))
3407
*p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
3408
}
3409
3410
static void DemoWindowWidgetsTabs()
3411
{
3412
IMGUI_DEMO_MARKER("Widgets/Tabs");
3413
if (ImGui::TreeNode("Tabs"))
3414
{
3415
IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
3416
if (ImGui::TreeNode("Basic"))
3417
{
3418
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
3419
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
3420
{
3421
if (ImGui::BeginTabItem("Avocado"))
3422
{
3423
ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
3424
ImGui::EndTabItem();
3425
}
3426
if (ImGui::BeginTabItem("Broccoli"))
3427
{
3428
ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
3429
ImGui::EndTabItem();
3430
}
3431
if (ImGui::BeginTabItem("Cucumber"))
3432
{
3433
ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
3434
ImGui::EndTabItem();
3435
}
3436
ImGui::EndTabBar();
3437
}
3438
ImGui::Separator();
3439
ImGui::TreePop();
3440
}
3441
3442
IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
3443
if (ImGui::TreeNode("Advanced & Close Button"))
3444
{
3445
// Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
3446
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
3447
ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
3448
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
3449
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
3450
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
3451
ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
3452
EditTabBarFittingPolicyFlags(&tab_bar_flags);
3453
3454
// Tab Bar
3455
ImGui::AlignTextToFramePadding();
3456
ImGui::Text("Opened:");
3457
const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
3458
static bool opened[4] = { true, true, true, true }; // Persistent user state
3459
for (int n = 0; n < IM_COUNTOF(opened); n++)
3460
{
3461
ImGui::SameLine();
3462
ImGui::Checkbox(names[n], &opened[n]);
3463
}
3464
3465
// Passing a bool* to BeginTabItem() is similar to passing one to Begin():
3466
// the underlying bool will be set to false when the tab is closed.
3467
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
3468
{
3469
for (int n = 0; n < IM_COUNTOF(opened); n++)
3470
if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
3471
{
3472
ImGui::Text("This is the %s tab!", names[n]);
3473
if (n & 1)
3474
ImGui::Text("I am an odd tab.");
3475
ImGui::EndTabItem();
3476
}
3477
ImGui::EndTabBar();
3478
}
3479
ImGui::Separator();
3480
ImGui::TreePop();
3481
}
3482
3483
IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
3484
if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
3485
{
3486
static ImVector<int> active_tabs;
3487
static int next_tab_id = 0;
3488
if (next_tab_id == 0) // Initialize with some default tabs
3489
for (int i = 0; i < 3; i++)
3490
active_tabs.push_back(next_tab_id++);
3491
3492
// TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
3493
// (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
3494
// but they tend to make more sense together)
3495
static bool show_leading_button = true;
3496
static bool show_trailing_button = true;
3497
ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
3498
ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
3499
3500
// Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
3501
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyShrink;
3502
EditTabBarFittingPolicyFlags(&tab_bar_flags);
3503
3504
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
3505
{
3506
// Demo a Leading TabItemButton(): click the "?" button to open a menu
3507
if (show_leading_button)
3508
if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
3509
ImGui::OpenPopup("MyHelpMenu");
3510
if (ImGui::BeginPopup("MyHelpMenu"))
3511
{
3512
ImGui::Selectable("Hello!");
3513
ImGui::EndPopup();
3514
}
3515
3516
// Demo Trailing Tabs: click the "+" button to add a new tab.
3517
// (In your app you may want to use a font icon instead of the "+")
3518
// We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
3519
if (show_trailing_button)
3520
if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
3521
active_tabs.push_back(next_tab_id++); // Add new tab
3522
3523
// Submit our regular tabs
3524
for (int n = 0; n < active_tabs.Size; )
3525
{
3526
bool open = true;
3527
char name[16];
3528
snprintf(name, IM_COUNTOF(name), "%04d", active_tabs[n]);
3529
if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
3530
{
3531
ImGui::Text("This is the %s tab!", name);
3532
ImGui::EndTabItem();
3533
}
3534
3535
if (!open)
3536
active_tabs.erase(active_tabs.Data + n);
3537
else
3538
n++;
3539
}
3540
3541
ImGui::EndTabBar();
3542
}
3543
ImGui::Separator();
3544
ImGui::TreePop();
3545
}
3546
ImGui::TreePop();
3547
}
3548
}
3549
3550
//-----------------------------------------------------------------------------
3551
// [SECTION] DemoWindowWidgetsText()
3552
//-----------------------------------------------------------------------------
3553
3554
static void DemoWindowWidgetsText()
3555
{
3556
IMGUI_DEMO_MARKER("Widgets/Text");
3557
if (ImGui::TreeNode("Text"))
3558
{
3559
IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
3560
if (ImGui::TreeNode("Colorful Text"))
3561
{
3562
// Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
3563
ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
3564
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
3565
ImGui::TextDisabled("Disabled");
3566
ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
3567
ImGui::TreePop();
3568
}
3569
3570
IMGUI_DEMO_MARKER("Widgets/Text/Font Size");
3571
if (ImGui::TreeNode("Font Size"))
3572
{
3573
ImGuiStyle& style = ImGui::GetStyle();
3574
const float global_scale = style.FontScaleMain * style.FontScaleDpi;
3575
ImGui::Text("style.FontScaleMain = %0.2f", style.FontScaleMain);
3576
ImGui::Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi);
3577
ImGui::Text("global_scale = ~%0.2f", global_scale); // This is not technically accurate as internal scales may apply, but conceptually let's pretend it is.
3578
ImGui::Text("FontSize = %0.2f", ImGui::GetFontSize());
3579
3580
ImGui::SeparatorText("");
3581
static float custom_size = 16.0f;
3582
ImGui::SliderFloat("custom_size", &custom_size, 10.0f, 100.0f, "%.0f");
3583
ImGui::Text("ImGui::PushFont(nullptr, custom_size);");
3584
ImGui::PushFont(NULL, custom_size, -1.0f);
3585
ImGui::Text("FontSize = %.2f (== %.2f * global_scale)", ImGui::GetFontSize(), custom_size);
3586
ImGui::PopFont();
3587
3588
ImGui::SeparatorText("");
3589
static float custom_scale = 1.0f;
3590
ImGui::SliderFloat("custom_scale", &custom_scale, 0.5f, 4.0f, "%.2f");
3591
ImGui::Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);");
3592
ImGui::PushFont(NULL, style.FontSizeBase * custom_scale, -1.0f);
3593
ImGui::Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui::GetFontSize(), custom_scale);
3594
ImGui::PopFont();
3595
3596
ImGui::SeparatorText("");
3597
for (float scaling = 0.5f; scaling <= 4.0f; scaling += 0.5f)
3598
{
3599
ImGui::PushFont(NULL, style.FontSizeBase * scaling, -1.0f);
3600
ImGui::Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui::GetFontSize(), scaling);
3601
ImGui::PopFont();
3602
}
3603
3604
ImGui::TreePop();
3605
}
3606
3607
IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
3608
if (ImGui::TreeNode("Word Wrapping"))
3609
{
3610
// Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
3611
ImGui::TextWrapped(
3612
"This text should automatically wrap on the edge of the window. The current implementation "
3613
"for text wrapping follows simple rules suitable for English and possibly other languages.");
3614
ImGui::Spacing();
3615
3616
static float wrap_width = 200.0f;
3617
ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
3618
3619
ImDrawList* draw_list = ImGui::GetWindowDrawList();
3620
for (int n = 0; n < 2; n++)
3621
{
3622
ImGui::Text("Test paragraph %d:", n);
3623
ImVec2 pos = ImGui::GetCursorScreenPos();
3624
ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
3625
ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
3626
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
3627
if (n == 0)
3628
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);
3629
else
3630
ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
3631
3632
// Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
3633
draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
3634
draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
3635
ImGui::PopTextWrapPos();
3636
}
3637
3638
ImGui::TreePop();
3639
}
3640
3641
IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
3642
if (ImGui::TreeNode("UTF-8 Text"))
3643
{
3644
// UTF-8 test with Japanese characters
3645
// (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
3646
// - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
3647
// - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
3648
// can save your source files as 'UTF-8 without signature').
3649
// - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
3650
// CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
3651
// Don't do this in your application! Please use u8"text in any language" in your application!
3652
// Note that characters values are preserved even by InputText() if the font cannot be displayed,
3653
// so you can safely copy & paste garbled characters into another application.
3654
ImGui::TextWrapped(
3655
"CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
3656
"Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
3657
"Read docs/FONTS.md for details.");
3658
ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
3659
ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
3660
static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
3661
//static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
3662
ImGui::InputText("UTF-8 input", buf, IM_COUNTOF(buf));
3663
ImGui::TreePop();
3664
}
3665
ImGui::TreePop();
3666
}
3667
}
3668
3669
//-----------------------------------------------------------------------------
3670
// [SECTION] DemoWindowWidgetsTextFilter()
3671
//-----------------------------------------------------------------------------
3672
3673
static void DemoWindowWidgetsTextFilter()
3674
{
3675
IMGUI_DEMO_MARKER("Widgets/Text Filter");
3676
if (ImGui::TreeNode("Text Filter"))
3677
{
3678
// Helper class to easy setup a text filter.
3679
// You may want to implement a more feature-full filtering scheme in your own application.
3680
HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
3681
static ImGuiTextFilter filter;
3682
ImGui::Text("Filter usage:\n"
3683
" \"\" display all lines\n"
3684
" \"xxx\" display lines containing \"xxx\"\n"
3685
" \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
3686
" \"-xxx\" hide lines containing \"xxx\"");
3687
filter.Draw();
3688
const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
3689
for (int i = 0; i < IM_COUNTOF(lines); i++)
3690
if (filter.PassFilter(lines[i]))
3691
ImGui::BulletText("%s", lines[i]);
3692
ImGui::TreePop();
3693
}
3694
}
3695
3696
//-----------------------------------------------------------------------------
3697
// [SECTION] DemoWindowWidgetsTextInput()
3698
//-----------------------------------------------------------------------------
3699
3700
static void DemoWindowWidgetsTextInput()
3701
{
3702
// To wire InputText() with std::string or any other custom string type,
3703
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
3704
IMGUI_DEMO_MARKER("Widgets/Text Input");
3705
if (ImGui::TreeNode("Text Input"))
3706
{
3707
IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
3708
if (ImGui::TreeNode("Multi-line Text Input"))
3709
{
3710
// WE ARE USING A FIXED-SIZE BUFFER FOR SIMPLICITY HERE.
3711
// If you want to use InputText() with std::string or any custom dynamic string type:
3712
// - For std::string: use the wrapper in misc/cpp/imgui_stdlib.h/.cpp
3713
// - Otherwise, see the 'Dear ImGui Demo->Widgets->Text Input->Resize Callback' for using ImGuiInputTextFlags_CallbackResize.
3714
static char text[1024 * 16] =
3715
"/*\n"
3716
" The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
3717
" the hexadecimal encoding of one offending instruction,\n"
3718
" more formally, the invalid operand with locked CMPXCHG8B\n"
3719
" instruction bug, is a design flaw in the majority of\n"
3720
" Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
3721
" processors (all in the P5 microarchitecture).\n"
3722
"*/\n\n"
3723
"label:\n"
3724
"\tlock cmpxchg8b eax\n";
3725
3726
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
3727
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)");
3728
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
3729
ImGui::CheckboxFlags("ImGuiInputTextFlags_WordWrap", &flags, ImGuiInputTextFlags_WordWrap);
3730
ImGui::SameLine(); HelpMarker("Feature is currently in Beta. Please read comments in imgui.h");
3731
ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
3732
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.");
3733
ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
3734
ImGui::InputTextMultiline("##source", text, IM_COUNTOF(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
3735
ImGui::TreePop();
3736
}
3737
3738
IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
3739
if (ImGui::TreeNode("Filtered Text Input"))
3740
{
3741
struct TextFilters
3742
{
3743
// Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
3744
static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
3745
{
3746
if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
3747
else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
3748
return 0;
3749
}
3750
3751
// Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
3752
static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
3753
{
3754
if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
3755
return 0;
3756
return 1;
3757
}
3758
};
3759
3760
static char buf1[32] = ""; ImGui::InputText("default", buf1, IM_COUNTOF(buf1));
3761
static char buf2[32] = ""; ImGui::InputText("decimal", buf2, IM_COUNTOF(buf2), ImGuiInputTextFlags_CharsDecimal);
3762
static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, IM_COUNTOF(buf3), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
3763
static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, IM_COUNTOF(buf4), ImGuiInputTextFlags_CharsUppercase);
3764
static char buf5[32] = ""; ImGui::InputText("no blank", buf5, IM_COUNTOF(buf5), ImGuiInputTextFlags_CharsNoBlank);
3765
static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, IM_COUNTOF(buf6), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
3766
static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, IM_COUNTOF(buf7), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
3767
ImGui::TreePop();
3768
}
3769
3770
IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
3771
if (ImGui::TreeNode("Password Input"))
3772
{
3773
static char password[64] = "password123";
3774
ImGui::InputText("password", password, IM_COUNTOF(password), ImGuiInputTextFlags_Password);
3775
ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
3776
ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_COUNTOF(password), ImGuiInputTextFlags_Password);
3777
ImGui::InputText("password (clear)", password, IM_COUNTOF(password));
3778
ImGui::TreePop();
3779
}
3780
3781
IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
3782
if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
3783
{
3784
struct Funcs
3785
{
3786
static int MyCallback(ImGuiInputTextCallbackData* data)
3787
{
3788
if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
3789
{
3790
data->InsertChars(data->CursorPos, "..");
3791
}
3792
else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
3793
{
3794
if (data->EventKey == ImGuiKey_UpArrow)
3795
{
3796
data->DeleteChars(0, data->BufTextLen);
3797
data->InsertChars(0, "Pressed Up!");
3798
data->SelectAll();
3799
}
3800
else if (data->EventKey == ImGuiKey_DownArrow)
3801
{
3802
data->DeleteChars(0, data->BufTextLen);
3803
data->InsertChars(0, "Pressed Down!");
3804
data->SelectAll();
3805
}
3806
}
3807
else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
3808
{
3809
// Toggle casing of first character
3810
char c = data->Buf[0];
3811
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
3812
data->BufDirty = true;
3813
3814
// Increment a counter
3815
int* p_int = (int*)data->UserData;
3816
*p_int = *p_int + 1;
3817
}
3818
return 0;
3819
}
3820
};
3821
static char buf1[64];
3822
ImGui::InputText("Completion", buf1, IM_COUNTOF(buf1), ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
3823
ImGui::SameLine(); HelpMarker(
3824
"Here we append \"..\" each time Tab is pressed. "
3825
"See 'Examples>Console' for a more meaningful demonstration of using this callback.");
3826
3827
static char buf2[64];
3828
ImGui::InputText("History", buf2, IM_COUNTOF(buf2), ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
3829
ImGui::SameLine(); HelpMarker(
3830
"Here we replace and select text each time Up/Down are pressed. "
3831
"See 'Examples>Console' for a more meaningful demonstration of using this callback.");
3832
3833
static char buf3[64];
3834
static int edit_count = 0;
3835
ImGui::InputText("Edit", buf3, IM_COUNTOF(buf3), ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
3836
ImGui::SameLine(); HelpMarker(
3837
"Here we toggle the casing of the first character on every edit + count edits.");
3838
ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
3839
3840
ImGui::TreePop();
3841
}
3842
3843
IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
3844
if (ImGui::TreeNode("Resize Callback"))
3845
{
3846
// To wire InputText() with std::string or any other custom string type,
3847
// you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
3848
// using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
3849
HelpMarker(
3850
"Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
3851
"See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
3852
struct Funcs
3853
{
3854
static int MyResizeCallback(ImGuiInputTextCallbackData* data)
3855
{
3856
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
3857
{
3858
ImVector<char>* my_str = (ImVector<char>*)data->UserData;
3859
IM_ASSERT(my_str->begin() == data->Buf);
3860
my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
3861
data->Buf = my_str->begin();
3862
}
3863
return 0;
3864
}
3865
3866
// Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
3867
// For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
3868
static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
3869
{
3870
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
3871
return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
3872
}
3873
};
3874
3875
// For this demo we are using ImVector as a string container.
3876
// Note that because we need to store a terminating zero character, our size/capacity are 1 more
3877
// than usually reported by a typical string class.
3878
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
3879
ImGui::CheckboxFlags("ImGuiInputTextFlags_WordWrap", &flags, ImGuiInputTextFlags_WordWrap);
3880
3881
static ImVector<char> my_str;
3882
if (my_str.empty())
3883
my_str.push_back(0);
3884
Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
3885
ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
3886
ImGui::TreePop();
3887
}
3888
3889
IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment");
3890
if (ImGui::TreeNode("Eliding, Alignment"))
3891
{
3892
static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp";
3893
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft;
3894
ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft);
3895
ImGui::InputText("Path", buf1, IM_COUNTOF(buf1), flags);
3896
ImGui::TreePop();
3897
}
3898
3899
IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
3900
if (ImGui::TreeNode("Miscellaneous"))
3901
{
3902
static char buf1[16];
3903
static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
3904
ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
3905
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
3906
ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
3907
ImGui::InputText("Hello", buf1, IM_COUNTOF(buf1), flags);
3908
ImGui::TreePop();
3909
}
3910
3911
ImGui::TreePop();
3912
}
3913
3914
}
3915
3916
//-----------------------------------------------------------------------------
3917
// [SECTION] DemoWindowWidgetsTooltips()
3918
//-----------------------------------------------------------------------------
3919
3920
static void DemoWindowWidgetsTooltips()
3921
{
3922
IMGUI_DEMO_MARKER("Widgets/Tooltips");
3923
if (ImGui::TreeNode("Tooltips"))
3924
{
3925
// Tooltips are windows following the mouse. They do not take focus away.
3926
ImGui::SeparatorText("General");
3927
3928
// Typical use cases:
3929
// - Short-form (text only): SetItemTooltip("Hello");
3930
// - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
3931
3932
// - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); }
3933
// - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
3934
3935
HelpMarker(
3936
"Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
3937
"We provide a helper SetItemTooltip() function to perform the two with standards flags.");
3938
3939
ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
3940
3941
ImGui::Button("Basic", sz);
3942
ImGui::SetItemTooltip("I am a tooltip");
3943
3944
ImGui::Button("Fancy", sz);
3945
if (ImGui::BeginItemTooltip())
3946
{
3947
ImGui::Text("I am a fancy tooltip");
3948
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
3949
ImGui::PlotLines("Curve", arr, IM_COUNTOF(arr));
3950
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
3951
ImGui::EndTooltip();
3952
}
3953
3954
ImGui::SeparatorText("Always On");
3955
3956
// Showcase NOT relying on a IsItemHovered() to emit a tooltip.
3957
// Here the tooltip is always emitted when 'always_on == true'.
3958
static int always_on = 0;
3959
ImGui::RadioButton("Off", &always_on, 0);
3960
ImGui::SameLine();
3961
ImGui::RadioButton("Always On (Simple)", &always_on, 1);
3962
ImGui::SameLine();
3963
ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
3964
if (always_on == 1)
3965
ImGui::SetTooltip("I am following you around.");
3966
else if (always_on == 2 && ImGui::BeginTooltip())
3967
{
3968
ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
3969
ImGui::EndTooltip();
3970
}
3971
3972
ImGui::SeparatorText("Custom");
3973
3974
HelpMarker(
3975
"Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize "
3976
"tooltip activation details across your application. You may however decide to use custom "
3977
"flags for a specific tooltip instance.");
3978
3979
// The following examples are passed for documentation purpose but may not be useful to most users.
3980
// Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
3981
// 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used.
3982
// With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
3983
ImGui::Button("Manual", sz);
3984
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
3985
ImGui::SetTooltip("I am a manually emitted tooltip.");
3986
3987
ImGui::Button("DelayNone", sz);
3988
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
3989
ImGui::SetTooltip("I am a tooltip with no delay.");
3990
3991
ImGui::Button("DelayShort", sz);
3992
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
3993
ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
3994
3995
ImGui::Button("DelayLong", sz);
3996
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
3997
ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
3998
3999
ImGui::Button("Stationary", sz);
4000
if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
4001
ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
4002
4003
// Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
4004
// which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
4005
ImGui::BeginDisabled();
4006
ImGui::Button("Disabled item", sz);
4007
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
4008
ImGui::SetTooltip("I am a a tooltip for a disabled item.");
4009
ImGui::EndDisabled();
4010
4011
ImGui::TreePop();
4012
}
4013
}
4014
4015
//-----------------------------------------------------------------------------
4016
// [SECTION] DemoWindowWidgetsTreeNodes()
4017
//-----------------------------------------------------------------------------
4018
4019
static void DemoWindowWidgetsTreeNodes()
4020
{
4021
IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
4022
if (ImGui::TreeNode("Tree Nodes"))
4023
{
4024
// See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree.
4025
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
4026
if (ImGui::TreeNode("Basic trees"))
4027
{
4028
for (int i = 0; i < 5; i++)
4029
{
4030
// Use SetNextItemOpen() so set the default state of a node to be open. We could
4031
// also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
4032
if (i == 0)
4033
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
4034
4035
// Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict.
4036
// An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)',
4037
// aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine.
4038
ImGui::PushID(i);
4039
if (ImGui::TreeNode("", "Child %d", i))
4040
{
4041
ImGui::Text("blah blah");
4042
ImGui::SameLine();
4043
if (ImGui::SmallButton("button")) {}
4044
ImGui::TreePop();
4045
}
4046
ImGui::PopID();
4047
}
4048
ImGui::TreePop();
4049
}
4050
4051
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy lines");
4052
if (ImGui::TreeNode("Hierarchy lines"))
4053
{
4054
static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DefaultOpen;
4055
HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
4056
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone);
4057
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull);
4058
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes);
4059
4060
if (ImGui::TreeNodeEx("Parent", base_flags))
4061
{
4062
if (ImGui::TreeNodeEx("Child 1", base_flags))
4063
{
4064
ImGui::Button("Button for Child 1");
4065
ImGui::TreePop();
4066
}
4067
if (ImGui::TreeNodeEx("Child 2", base_flags))
4068
{
4069
ImGui::Button("Button for Child 2");
4070
ImGui::TreePop();
4071
}
4072
ImGui::Text("Remaining contents");
4073
ImGui::Text("Remaining contents");
4074
ImGui::TreePop();
4075
}
4076
4077
ImGui::TreePop();
4078
}
4079
4080
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
4081
if (ImGui::TreeNode("Advanced, with Selectable nodes"))
4082
{
4083
HelpMarker(
4084
"This is a more typical looking tree with selectable nodes.\n"
4085
"Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.");
4086
static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
4087
static bool align_label_with_current_x_position = false;
4088
static bool test_drag_and_drop = false;
4089
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
4090
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
4091
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.");
4092
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
4093
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.");
4094
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
4095
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
4096
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
4097
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_FramePadding", &base_flags, ImGuiTreeNodeFlags_FramePadding);
4098
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsToParent);
4099
4100
HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
4101
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone);
4102
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull);
4103
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes);
4104
4105
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
4106
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
4107
ImGui::Text("Hello!");
4108
if (align_label_with_current_x_position)
4109
ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
4110
4111
// 'selection_mask' is dumb representation of what may be user-side selection state.
4112
// You may retain selection state inside or outside your objects in whatever format you see fit.
4113
// 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
4114
/// of the loop. May be a pointer to your own node type, etc.
4115
static int selection_mask = (1 << 2);
4116
int node_clicked = -1;
4117
for (int i = 0; i < 6; i++)
4118
{
4119
// Disable the default "open on single-click behavior" + set Selected flag according to our selection.
4120
// To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
4121
ImGuiTreeNodeFlags node_flags = base_flags;
4122
const bool is_selected = (selection_mask & (1 << i)) != 0;
4123
if (is_selected)
4124
node_flags |= ImGuiTreeNodeFlags_Selected;
4125
if (i < 3)
4126
{
4127
// Items 0..2 are Tree Node
4128
bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
4129
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
4130
node_clicked = i;
4131
if (test_drag_and_drop && ImGui::BeginDragDropSource())
4132
{
4133
ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
4134
ImGui::Text("This is a drag and drop source");
4135
ImGui::EndDragDropSource();
4136
}
4137
if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth))
4138
{
4139
// Item 2 has an additional inline button to help demonstrate SpanLabelWidth.
4140
ImGui::SameLine();
4141
if (ImGui::SmallButton("button")) {}
4142
}
4143
if (node_open)
4144
{
4145
ImGui::BulletText("Blah blah\nBlah Blah");
4146
ImGui::SameLine();
4147
ImGui::SmallButton("Button");
4148
ImGui::TreePop();
4149
}
4150
}
4151
else
4152
{
4153
// Items 3..5 are Tree Leaves
4154
// The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
4155
// use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
4156
node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
4157
ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
4158
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
4159
node_clicked = i;
4160
if (test_drag_and_drop && ImGui::BeginDragDropSource())
4161
{
4162
ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
4163
ImGui::Text("This is a drag and drop source");
4164
ImGui::EndDragDropSource();
4165
}
4166
}
4167
}
4168
if (node_clicked != -1)
4169
{
4170
// Update selection state
4171
// (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
4172
if (ImGui::GetIO().KeyCtrl)
4173
selection_mask ^= (1 << node_clicked); // Ctrl+Click to toggle
4174
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
4175
selection_mask = (1 << node_clicked); // Click to single-select
4176
}
4177
if (align_label_with_current_x_position)
4178
ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
4179
ImGui::TreePop();
4180
}
4181
ImGui::TreePop();
4182
}
4183
}
4184
4185
//-----------------------------------------------------------------------------
4186
// [SECTION] DemoWindowWidgetsVerticalSliders()
4187
//-----------------------------------------------------------------------------
4188
4189
static void DemoWindowWidgetsVerticalSliders()
4190
{
4191
IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
4192
if (ImGui::TreeNode("Vertical Sliders"))
4193
{
4194
const float spacing = 4;
4195
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
4196
4197
static int int_value = 0;
4198
ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
4199
ImGui::SameLine();
4200
4201
static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
4202
ImGui::PushID("set1");
4203
for (int i = 0; i < 7; i++)
4204
{
4205
if (i > 0) ImGui::SameLine();
4206
ImGui::PushID(i);
4207
ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
4208
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
4209
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
4210
ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
4211
ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
4212
if (ImGui::IsItemActive() || ImGui::IsItemHovered())
4213
ImGui::SetTooltip("%.3f", values[i]);
4214
ImGui::PopStyleColor(4);
4215
ImGui::PopID();
4216
}
4217
ImGui::PopID();
4218
4219
ImGui::SameLine();
4220
ImGui::PushID("set2");
4221
static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
4222
const int rows = 3;
4223
const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
4224
for (int nx = 0; nx < 4; nx++)
4225
{
4226
if (nx > 0) ImGui::SameLine();
4227
ImGui::BeginGroup();
4228
for (int ny = 0; ny < rows; ny++)
4229
{
4230
ImGui::PushID(nx * rows + ny);
4231
ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
4232
if (ImGui::IsItemActive() || ImGui::IsItemHovered())
4233
ImGui::SetTooltip("%.3f", values2[nx]);
4234
ImGui::PopID();
4235
}
4236
ImGui::EndGroup();
4237
}
4238
ImGui::PopID();
4239
4240
ImGui::SameLine();
4241
ImGui::PushID("set3");
4242
for (int i = 0; i < 4; i++)
4243
{
4244
if (i > 0) ImGui::SameLine();
4245
ImGui::PushID(i);
4246
ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
4247
ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
4248
ImGui::PopStyleVar();
4249
ImGui::PopID();
4250
}
4251
ImGui::PopID();
4252
ImGui::PopStyleVar();
4253
ImGui::TreePop();
4254
}
4255
}
4256
4257
//-----------------------------------------------------------------------------
4258
// [SECTION] DemoWindowWidgets()
4259
//-----------------------------------------------------------------------------
4260
4261
static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data)
4262
{
4263
IMGUI_DEMO_MARKER("Widgets");
4264
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
4265
if (!ImGui::CollapsingHeader("Widgets"))
4266
return;
4267
4268
const bool disable_all = demo_data->DisableSections; // The Checkbox for that is inside the "Disabled" section at the bottom
4269
if (disable_all)
4270
ImGui::BeginDisabled();
4271
4272
DemoWindowWidgetsBasic();
4273
DemoWindowWidgetsBullets();
4274
DemoWindowWidgetsCollapsingHeaders();
4275
DemoWindowWidgetsComboBoxes();
4276
DemoWindowWidgetsColorAndPickers();
4277
DemoWindowWidgetsDataTypes();
4278
4279
if (disable_all)
4280
ImGui::EndDisabled();
4281
DemoWindowWidgetsDisableBlocks(demo_data);
4282
if (disable_all)
4283
ImGui::BeginDisabled();
4284
4285
DemoWindowWidgetsDragAndDrop();
4286
DemoWindowWidgetsDragsAndSliders();
4287
DemoWindowWidgetsFonts();
4288
DemoWindowWidgetsImages();
4289
DemoWindowWidgetsListBoxes();
4290
DemoWindowWidgetsMultiComponents();
4291
DemoWindowWidgetsPlotting();
4292
DemoWindowWidgetsProgressBars();
4293
DemoWindowWidgetsQueryingStatuses();
4294
DemoWindowWidgetsSelectables();
4295
DemoWindowWidgetsSelectionAndMultiSelect(demo_data);
4296
DemoWindowWidgetsTabs();
4297
DemoWindowWidgetsText();
4298
DemoWindowWidgetsTextFilter();
4299
DemoWindowWidgetsTextInput();
4300
DemoWindowWidgetsTooltips();
4301
DemoWindowWidgetsTreeNodes();
4302
DemoWindowWidgetsVerticalSliders();
4303
4304
if (disable_all)
4305
ImGui::EndDisabled();
4306
}
4307
4308
//-----------------------------------------------------------------------------
4309
// [SECTION] DemoWindowLayout()
4310
//-----------------------------------------------------------------------------
4311
4312
static void DemoWindowLayout()
4313
{
4314
IMGUI_DEMO_MARKER("Layout");
4315
if (!ImGui::CollapsingHeader("Layout & Scrolling"))
4316
return;
4317
4318
IMGUI_DEMO_MARKER("Layout/Child windows");
4319
if (ImGui::TreeNode("Child windows"))
4320
{
4321
ImGui::SeparatorText("Child windows");
4322
4323
HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
4324
static bool disable_mouse_wheel = false;
4325
static bool disable_menu = false;
4326
ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
4327
ImGui::Checkbox("Disable Menu", &disable_menu);
4328
4329
// Child 1: no border, enable horizontal scrollbar
4330
{
4331
ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
4332
if (disable_mouse_wheel)
4333
window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4334
ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags);
4335
for (int i = 0; i < 100; i++)
4336
ImGui::Text("%04d: scrollable region", i);
4337
ImGui::EndChild();
4338
}
4339
4340
ImGui::SameLine();
4341
4342
// Child 2: rounded border
4343
{
4344
ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
4345
if (disable_mouse_wheel)
4346
window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4347
if (!disable_menu)
4348
window_flags |= ImGuiWindowFlags_MenuBar;
4349
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
4350
ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags);
4351
if (!disable_menu && ImGui::BeginMenuBar())
4352
{
4353
if (ImGui::BeginMenu("Menu"))
4354
{
4355
ShowExampleMenuFile();
4356
ImGui::EndMenu();
4357
}
4358
ImGui::EndMenuBar();
4359
}
4360
if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
4361
{
4362
for (int i = 0; i < 100; i++)
4363
{
4364
char buf[32];
4365
sprintf(buf, "%03d", i);
4366
ImGui::TableNextColumn();
4367
ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4368
}
4369
ImGui::EndTable();
4370
}
4371
ImGui::EndChild();
4372
ImGui::PopStyleVar();
4373
}
4374
4375
// Child 3: manual-resize
4376
ImGui::SeparatorText("Manual-resize");
4377
{
4378
HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
4379
//if (ImGui::Button("Set Height to 200"))
4380
// ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f));
4381
4382
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
4383
if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
4384
for (int n = 0; n < 10; n++)
4385
ImGui::Text("Line %04d", n);
4386
ImGui::PopStyleColor();
4387
ImGui::EndChild();
4388
}
4389
4390
// Child 4: auto-resizing height with a limit
4391
ImGui::SeparatorText("Auto-resize with constraints");
4392
{
4393
static int draw_lines = 3;
4394
static int max_height_in_lines = 10;
4395
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4396
ImGui::DragInt("Lines Count", &draw_lines, 0.2f);
4397
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4398
ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
4399
4400
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
4401
if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY))
4402
for (int n = 0; n < draw_lines; n++)
4403
ImGui::Text("Line %04d", n);
4404
ImGui::EndChild();
4405
}
4406
4407
ImGui::SeparatorText("Misc/Advanced");
4408
4409
// Demonstrate a few extra things
4410
// - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
4411
// - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
4412
// You can also call SetNextWindowPos() to position the child window. The parent window will effectively
4413
// layout from this position.
4414
// - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
4415
// the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
4416
{
4417
static int offset_x = 0;
4418
static bool override_bg_color = true;
4419
static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
4420
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4421
ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
4422
ImGui::Checkbox("Override ChildBg color", &override_bg_color);
4423
ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders);
4424
ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
4425
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
4426
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
4427
ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle);
4428
ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
4429
if (child_flags & ImGuiChildFlags_FrameStyle)
4430
override_bg_color = false;
4431
4432
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
4433
if (override_bg_color)
4434
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
4435
ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
4436
if (override_bg_color)
4437
ImGui::PopStyleColor();
4438
4439
for (int n = 0; n < 50; n++)
4440
ImGui::Text("Some test %d", n);
4441
ImGui::EndChild();
4442
bool child_is_hovered = ImGui::IsItemHovered();
4443
ImVec2 child_rect_min = ImGui::GetItemRectMin();
4444
ImVec2 child_rect_max = ImGui::GetItemRectMax();
4445
ImGui::Text("Hovered: %d", child_is_hovered);
4446
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);
4447
}
4448
4449
ImGui::TreePop();
4450
}
4451
4452
IMGUI_DEMO_MARKER("Layout/Widgets Width");
4453
if (ImGui::TreeNode("Widgets Width"))
4454
{
4455
static float f = 0.0f;
4456
static bool show_indented_items = true;
4457
ImGui::Checkbox("Show indented items", &show_indented_items);
4458
4459
// Use SetNextItemWidth() to set the width of a single upcoming item.
4460
// Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
4461
// In real code use you'll probably want to choose width values that are proportional to your font size
4462
// e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
4463
4464
ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
4465
ImGui::SameLine(); HelpMarker("Fixed width.");
4466
ImGui::PushItemWidth(100);
4467
ImGui::DragFloat("float##1b", &f);
4468
if (show_indented_items)
4469
{
4470
ImGui::Indent();
4471
ImGui::DragFloat("float (indented)##1b", &f);
4472
ImGui::Unindent();
4473
}
4474
ImGui::PopItemWidth();
4475
4476
ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
4477
ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
4478
ImGui::PushItemWidth(-100);
4479
ImGui::DragFloat("float##2a", &f);
4480
if (show_indented_items)
4481
{
4482
ImGui::Indent();
4483
ImGui::DragFloat("float (indented)##2b", &f);
4484
ImGui::Unindent();
4485
}
4486
ImGui::PopItemWidth();
4487
4488
ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
4489
ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
4490
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
4491
ImGui::DragFloat("float##3a", &f);
4492
if (show_indented_items)
4493
{
4494
ImGui::Indent();
4495
ImGui::DragFloat("float (indented)##3b", &f);
4496
ImGui::Unindent();
4497
}
4498
ImGui::PopItemWidth();
4499
4500
ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
4501
ImGui::SameLine(); HelpMarker("Align to right edge minus half");
4502
ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
4503
ImGui::DragFloat("float##4a", &f);
4504
if (show_indented_items)
4505
{
4506
ImGui::Indent();
4507
ImGui::DragFloat("float (indented)##4b", &f);
4508
ImGui::Unindent();
4509
}
4510
ImGui::PopItemWidth();
4511
4512
ImGui::Text("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))");
4513
ImGui::PushItemWidth(-IM_MIN(ImGui::GetFontSize() * 12, ImGui::GetContentRegionAvail().x * 0.40f));
4514
ImGui::DragFloat("float##5a", &f);
4515
if (show_indented_items)
4516
{
4517
ImGui::Indent();
4518
ImGui::DragFloat("float (indented)##5b", &f);
4519
ImGui::Unindent();
4520
}
4521
ImGui::PopItemWidth();
4522
4523
// Demonstrate using PushItemWidth to surround three items.
4524
// Calling SetNextItemWidth() before each of them would have the same effect.
4525
ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
4526
ImGui::SameLine(); HelpMarker("Align to right edge");
4527
ImGui::PushItemWidth(-FLT_MIN);
4528
ImGui::DragFloat("##float6a", &f);
4529
if (show_indented_items)
4530
{
4531
ImGui::Indent();
4532
ImGui::DragFloat("float (indented)##6b", &f);
4533
ImGui::Unindent();
4534
}
4535
ImGui::PopItemWidth();
4536
4537
ImGui::TreePop();
4538
}
4539
4540
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
4541
if (ImGui::TreeNode("Basic Horizontal Layout"))
4542
{
4543
ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
4544
4545
// Text
4546
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
4547
ImGui::Text("Two items: Hello"); ImGui::SameLine();
4548
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4549
4550
// Adjust spacing
4551
ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
4552
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4553
4554
// Button
4555
ImGui::AlignTextToFramePadding();
4556
ImGui::Text("Normal buttons"); ImGui::SameLine();
4557
ImGui::Button("Banana"); ImGui::SameLine();
4558
ImGui::Button("Apple"); ImGui::SameLine();
4559
ImGui::Button("Corniflower");
4560
4561
// Button
4562
ImGui::Text("Small buttons"); ImGui::SameLine();
4563
ImGui::SmallButton("Like this one"); ImGui::SameLine();
4564
ImGui::Text("can fit within a text block.");
4565
4566
// Aligned to arbitrary position. Easy/cheap column.
4567
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
4568
ImGui::Text("Aligned");
4569
ImGui::SameLine(150); ImGui::Text("x=150");
4570
ImGui::SameLine(300); ImGui::Text("x=300");
4571
ImGui::Text("Aligned");
4572
ImGui::SameLine(150); ImGui::SmallButton("x=150");
4573
ImGui::SameLine(300); ImGui::SmallButton("x=300");
4574
4575
// Checkbox
4576
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
4577
static bool c1 = false, c2 = false, c3 = false, c4 = false;
4578
ImGui::Checkbox("My", &c1); ImGui::SameLine();
4579
ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
4580
ImGui::Checkbox("Is", &c3); ImGui::SameLine();
4581
ImGui::Checkbox("Rich", &c4);
4582
4583
// Various
4584
static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
4585
ImGui::PushItemWidth(ImGui::CalcTextSize("AAAAAAA").x);
4586
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
4587
static int item = -1;
4588
ImGui::Combo("Combo", &item, items, IM_COUNTOF(items)); ImGui::SameLine();
4589
ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
4590
ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
4591
ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
4592
4593
ImGui::Text("Lists:");
4594
static int selection[4] = { 0, 1, 2, 3 };
4595
for (int i = 0; i < 4; i++)
4596
{
4597
if (i > 0) ImGui::SameLine();
4598
ImGui::PushID(i);
4599
ImGui::ListBox("", &selection[i], items, IM_COUNTOF(items));
4600
ImGui::PopID();
4601
//ImGui::SetItemTooltip("ListBox %d hovered", i);
4602
}
4603
ImGui::PopItemWidth();
4604
4605
// Dummy
4606
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
4607
ImVec2 button_sz(40, 40);
4608
ImGui::Button("A", button_sz); ImGui::SameLine();
4609
ImGui::Dummy(button_sz); ImGui::SameLine();
4610
ImGui::Button("B", button_sz);
4611
4612
// Manually wrapping
4613
// (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
4614
IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
4615
ImGui::Text("Manual wrapping:");
4616
ImGuiStyle& style = ImGui::GetStyle();
4617
int buttons_count = 20;
4618
float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
4619
for (int n = 0; n < buttons_count; n++)
4620
{
4621
ImGui::PushID(n);
4622
ImGui::Button("Box", button_sz);
4623
float last_button_x2 = ImGui::GetItemRectMax().x;
4624
float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
4625
if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
4626
ImGui::SameLine();
4627
ImGui::PopID();
4628
}
4629
4630
ImGui::TreePop();
4631
}
4632
4633
IMGUI_DEMO_MARKER("Layout/Groups");
4634
if (ImGui::TreeNode("Groups"))
4635
{
4636
HelpMarker(
4637
"BeginGroup() basically locks the horizontal position for new line. "
4638
"EndGroup() bundles the whole group so that you can use \"item\" functions such as "
4639
"IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
4640
ImGui::BeginGroup();
4641
{
4642
ImGui::BeginGroup();
4643
ImGui::Button("AAA");
4644
ImGui::SameLine();
4645
ImGui::Button("BBB");
4646
ImGui::SameLine();
4647
ImGui::BeginGroup();
4648
ImGui::Button("CCC");
4649
ImGui::Button("DDD");
4650
ImGui::EndGroup();
4651
ImGui::SameLine();
4652
ImGui::Button("EEE");
4653
ImGui::EndGroup();
4654
ImGui::SetItemTooltip("First group hovered");
4655
}
4656
// Capture the group size and create widgets using the same size
4657
ImVec2 size = ImGui::GetItemRectSize();
4658
const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
4659
ImGui::PlotHistogram("##values", values, IM_COUNTOF(values), 0, NULL, 0.0f, 1.0f, size);
4660
4661
ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4662
ImGui::SameLine();
4663
ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4664
ImGui::EndGroup();
4665
ImGui::SameLine();
4666
4667
ImGui::Button("LEVERAGE\nBUZZWORD", size);
4668
ImGui::SameLine();
4669
4670
if (ImGui::BeginListBox("List", size))
4671
{
4672
ImGui::Selectable("Selected", true);
4673
ImGui::Selectable("Not Selected", false);
4674
ImGui::EndListBox();
4675
}
4676
4677
ImGui::TreePop();
4678
}
4679
4680
IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
4681
if (ImGui::TreeNode("Text Baseline Alignment"))
4682
{
4683
{
4684
ImGui::BulletText("Text baseline:");
4685
ImGui::SameLine(); HelpMarker(
4686
"This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
4687
"Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
4688
ImGui::Indent();
4689
4690
ImGui::Text("KO Blahblah"); ImGui::SameLine();
4691
ImGui::Button("Some framed item"); ImGui::SameLine();
4692
HelpMarker("Baseline of button will look misaligned with text..");
4693
4694
// If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4695
// (because we don't know what's coming after the Text() statement, we need to move the text baseline
4696
// down by FramePadding.y ahead of time)
4697
ImGui::AlignTextToFramePadding();
4698
ImGui::Text("OK Blahblah"); ImGui::SameLine();
4699
ImGui::Button("Some framed item##2"); ImGui::SameLine();
4700
HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
4701
4702
// SmallButton() uses the same vertical padding as Text
4703
ImGui::Button("TEST##1"); ImGui::SameLine();
4704
ImGui::Text("TEST"); ImGui::SameLine();
4705
ImGui::SmallButton("TEST##2");
4706
4707
// If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4708
ImGui::AlignTextToFramePadding();
4709
ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
4710
ImGui::Button("Item##1"); ImGui::SameLine();
4711
ImGui::Text("Item"); ImGui::SameLine();
4712
ImGui::SmallButton("Item##2"); ImGui::SameLine();
4713
ImGui::Button("Item##3");
4714
4715
ImGui::Unindent();
4716
}
4717
4718
ImGui::Spacing();
4719
4720
{
4721
ImGui::BulletText("Multi-line text:");
4722
ImGui::Indent();
4723
ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
4724
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4725
ImGui::Text("Banana");
4726
4727
ImGui::Text("Banana"); ImGui::SameLine();
4728
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4729
ImGui::Text("One\nTwo\nThree");
4730
4731
ImGui::Button("HOP##1"); ImGui::SameLine();
4732
ImGui::Text("Banana"); ImGui::SameLine();
4733
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4734
ImGui::Text("Banana");
4735
4736
ImGui::Button("HOP##2"); ImGui::SameLine();
4737
ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4738
ImGui::Text("Banana");
4739
ImGui::Unindent();
4740
}
4741
4742
ImGui::Spacing();
4743
4744
{
4745
ImGui::BulletText("Misc items:");
4746
ImGui::Indent();
4747
4748
// SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
4749
ImGui::Button("80x80", ImVec2(80, 80));
4750
ImGui::SameLine();
4751
ImGui::Button("50x50", ImVec2(50, 50));
4752
ImGui::SameLine();
4753
ImGui::Button("Button()");
4754
ImGui::SameLine();
4755
ImGui::SmallButton("SmallButton()");
4756
4757
// Tree
4758
// (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to disable hierarchy outline)
4759
const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
4760
ImGui::Button("Button##1"); // Will make line higher
4761
ImGui::SameLine(0.0f, spacing);
4762
if (ImGui::TreeNodeEx("Node##1", ImGuiTreeNodeFlags_DrawLinesNone))
4763
{
4764
// Placeholder tree data
4765
for (int i = 0; i < 6; i++)
4766
ImGui::BulletText("Item %d..", i);
4767
ImGui::TreePop();
4768
}
4769
4770
const float padding = (float)(int)(ImGui::GetFontSize() * 1.20f); // Large padding
4771
ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, padding);
4772
ImGui::Button("Button##2");
4773
ImGui::PopStyleVar();
4774
ImGui::SameLine(0.0f, spacing);
4775
if (ImGui::TreeNodeEx("Node##2", ImGuiTreeNodeFlags_DrawLinesNone))
4776
ImGui::TreePop();
4777
4778
// Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
4779
// Otherwise you can use SmallButton() (smaller fit).
4780
ImGui::AlignTextToFramePadding();
4781
4782
// Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
4783
// other contents "inside" the node.
4784
bool node_open = ImGui::TreeNode("Node##3");
4785
ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##3");
4786
if (node_open)
4787
{
4788
// Placeholder tree data
4789
for (int i = 0; i < 6; i++)
4790
ImGui::BulletText("Item %d..", i);
4791
ImGui::TreePop();
4792
}
4793
4794
// Bullet
4795
ImGui::Button("Button##4");
4796
ImGui::SameLine(0.0f, spacing);
4797
ImGui::BulletText("Bullet text");
4798
4799
ImGui::AlignTextToFramePadding();
4800
ImGui::BulletText("Node");
4801
ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##5");
4802
ImGui::Unindent();
4803
}
4804
4805
ImGui::TreePop();
4806
}
4807
4808
IMGUI_DEMO_MARKER("Layout/Scrolling");
4809
if (ImGui::TreeNode("Scrolling"))
4810
{
4811
// Vertical scroll functions
4812
IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
4813
HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
4814
4815
static int track_item = 50;
4816
static bool enable_track = true;
4817
static bool enable_extra_decorations = false;
4818
static float scroll_to_off_px = 0.0f;
4819
static float scroll_to_pos_px = 200.0f;
4820
4821
ImGui::Checkbox("Decoration", &enable_extra_decorations);
4822
4823
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
4824
enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
4825
ImGui::SameLine();
4826
ImGui::Checkbox("Track", &enable_track);
4827
4828
bool scroll_to_off = ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
4829
ImGui::SameLine();
4830
scroll_to_off |= ImGui::Button("Scroll Offset");
4831
4832
bool scroll_to_pos = ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
4833
ImGui::SameLine();
4834
scroll_to_pos |= ImGui::Button("Scroll To Pos");
4835
ImGui::PopItemWidth();
4836
4837
if (scroll_to_off || scroll_to_pos)
4838
enable_track = false;
4839
4840
ImGuiStyle& style = ImGui::GetStyle();
4841
float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
4842
if (child_w < 1.0f)
4843
child_w = 1.0f;
4844
ImGui::PushID("##VerticalScrolling");
4845
for (int i = 0; i < 5; i++)
4846
{
4847
if (i > 0) ImGui::SameLine();
4848
ImGui::BeginGroup();
4849
const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
4850
ImGui::TextUnformatted(names[i]);
4851
4852
const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
4853
const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4854
const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags);
4855
if (ImGui::BeginMenuBar())
4856
{
4857
ImGui::TextUnformatted("abc");
4858
ImGui::EndMenuBar();
4859
}
4860
if (scroll_to_off)
4861
ImGui::SetScrollY(scroll_to_off_px);
4862
if (scroll_to_pos)
4863
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
4864
if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4865
{
4866
for (int item = 0; item < 100; item++)
4867
{
4868
if (enable_track && item == track_item)
4869
{
4870
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4871
ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
4872
}
4873
else
4874
{
4875
ImGui::Text("Item %d", item);
4876
}
4877
}
4878
}
4879
float scroll_y = ImGui::GetScrollY();
4880
float scroll_max_y = ImGui::GetScrollMaxY();
4881
ImGui::EndChild();
4882
ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
4883
ImGui::EndGroup();
4884
}
4885
ImGui::PopID();
4886
4887
// Horizontal scroll functions
4888
IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
4889
ImGui::Spacing();
4890
HelpMarker(
4891
"Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
4892
"Because the clipping rectangle of most window hides half worth of WindowPadding on the "
4893
"left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
4894
"equivalent SetScrollFromPosY(+1) wouldn't.");
4895
ImGui::PushID("##HorizontalScrolling");
4896
for (int i = 0; i < 5; i++)
4897
{
4898
float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
4899
ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
4900
ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4901
bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags);
4902
if (scroll_to_off)
4903
ImGui::SetScrollX(scroll_to_off_px);
4904
if (scroll_to_pos)
4905
ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
4906
if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4907
{
4908
for (int item = 0; item < 100; item++)
4909
{
4910
if (item > 0)
4911
ImGui::SameLine();
4912
if (enable_track && item == track_item)
4913
{
4914
ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4915
ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
4916
}
4917
else
4918
{
4919
ImGui::Text("Item %d", item);
4920
}
4921
}
4922
}
4923
float scroll_x = ImGui::GetScrollX();
4924
float scroll_max_x = ImGui::GetScrollMaxX();
4925
ImGui::EndChild();
4926
ImGui::SameLine();
4927
const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
4928
ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
4929
ImGui::Spacing();
4930
}
4931
ImGui::PopID();
4932
4933
// Miscellaneous Horizontal Scrolling Demo
4934
IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
4935
HelpMarker(
4936
"Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
4937
"You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
4938
static int lines = 7;
4939
ImGui::SliderInt("Lines", &lines, 1, 15);
4940
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
4941
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
4942
ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
4943
ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
4944
for (int line = 0; line < lines; line++)
4945
{
4946
// Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
4947
// If you want to create your own time line for a real application you may be better off manipulating
4948
// the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
4949
// yourself. You may also want to use the lower-level ImDrawList API.
4950
int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
4951
for (int n = 0; n < num_buttons; n++)
4952
{
4953
if (n > 0) ImGui::SameLine();
4954
ImGui::PushID(n + line * 1000);
4955
char num_buf[16];
4956
sprintf(num_buf, "%d", n);
4957
const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
4958
float hue = n * 0.05f;
4959
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
4960
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
4961
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
4962
ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
4963
ImGui::PopStyleColor(3);
4964
ImGui::PopID();
4965
}
4966
}
4967
float scroll_x = ImGui::GetScrollX();
4968
float scroll_max_x = ImGui::GetScrollMaxX();
4969
ImGui::EndChild();
4970
ImGui::PopStyleVar(2);
4971
float scroll_x_delta = 0.0f;
4972
ImGui::SmallButton("<<");
4973
if (ImGui::IsItemActive())
4974
scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
4975
ImGui::SameLine();
4976
ImGui::Text("Scroll from code"); ImGui::SameLine();
4977
ImGui::SmallButton(">>");
4978
if (ImGui::IsItemActive())
4979
scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
4980
ImGui::SameLine();
4981
ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
4982
if (scroll_x_delta != 0.0f)
4983
{
4984
// Demonstrate a trick: you can use Begin to set yourself in the context of another window
4985
// (here we are already out of your child window)
4986
ImGui::BeginChild("scrolling");
4987
ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
4988
ImGui::EndChild();
4989
}
4990
ImGui::Spacing();
4991
4992
static bool show_horizontal_contents_size_demo_window = false;
4993
ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
4994
4995
if (show_horizontal_contents_size_demo_window)
4996
{
4997
static bool show_h_scrollbar = true;
4998
static bool show_button = true;
4999
static bool show_tree_nodes = true;
5000
static bool show_text_wrapped = false;
5001
static bool show_columns = true;
5002
static bool show_tab_bar = true;
5003
static bool show_child = false;
5004
static bool explicit_content_size = false;
5005
static float contents_size_x = 300.0f;
5006
if (explicit_content_size)
5007
ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
5008
ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
5009
IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
5010
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
5011
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
5012
HelpMarker(
5013
"Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
5014
"Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
5015
ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
5016
ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten)
5017
ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width
5018
ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
5019
ImGui::Checkbox("Columns", &show_columns); // Will use contents size
5020
ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size
5021
ImGui::Checkbox("Child", &show_child); // Will grow and use contents size
5022
ImGui::Checkbox("Explicit content size", &explicit_content_size);
5023
ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
5024
if (explicit_content_size)
5025
{
5026
ImGui::SameLine();
5027
ImGui::SetNextItemWidth(ImGui::CalcTextSize("123456").x);
5028
ImGui::DragFloat("##csx", &contents_size_x);
5029
ImVec2 p = ImGui::GetCursorScreenPos();
5030
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
5031
ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
5032
ImGui::Dummy(ImVec2(0, 10));
5033
}
5034
ImGui::PopStyleVar(2);
5035
ImGui::Separator();
5036
if (show_button)
5037
{
5038
ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
5039
}
5040
if (show_tree_nodes)
5041
{
5042
bool open = true;
5043
if (ImGui::TreeNode("this is a tree node"))
5044
{
5045
if (ImGui::TreeNode("another one of those tree node..."))
5046
{
5047
ImGui::Text("Some tree contents");
5048
ImGui::TreePop();
5049
}
5050
ImGui::TreePop();
5051
}
5052
ImGui::CollapsingHeader("CollapsingHeader", &open);
5053
}
5054
if (show_text_wrapped)
5055
{
5056
ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
5057
}
5058
if (show_columns)
5059
{
5060
ImGui::Text("Tables:");
5061
if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
5062
{
5063
for (int n = 0; n < 4; n++)
5064
{
5065
ImGui::TableNextColumn();
5066
ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
5067
}
5068
ImGui::EndTable();
5069
}
5070
ImGui::Text("Columns:");
5071
ImGui::Columns(4);
5072
for (int n = 0; n < 4; n++)
5073
{
5074
ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
5075
ImGui::NextColumn();
5076
}
5077
ImGui::Columns(1);
5078
}
5079
if (show_tab_bar && ImGui::BeginTabBar("Hello"))
5080
{
5081
if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
5082
if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
5083
if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
5084
if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
5085
ImGui::EndTabBar();
5086
}
5087
if (show_child)
5088
{
5089
ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders);
5090
ImGui::EndChild();
5091
}
5092
ImGui::End();
5093
}
5094
5095
ImGui::TreePop();
5096
}
5097
5098
IMGUI_DEMO_MARKER("Layout/Text Clipping");
5099
if (ImGui::TreeNode("Text Clipping"))
5100
{
5101
static ImVec2 size(100.0f, 100.0f);
5102
static ImVec2 offset(30.0f, 30.0f);
5103
ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
5104
ImGui::TextWrapped("(Click and drag to scroll)");
5105
5106
HelpMarker(
5107
"(Left) Using ImGui::PushClipRect():\n"
5108
"Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
5109
"(use this if you want your clipping rectangle to affect interactions)\n\n"
5110
"(Center) Using ImDrawList::PushClipRect():\n"
5111
"Will alter ImDrawList rendering only.\n"
5112
"(use this as a shortcut if you are only using ImDrawList calls)\n\n"
5113
"(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
5114
"Will alter only this specific ImDrawList::AddText() rendering.\n"
5115
"This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
5116
5117
for (int n = 0; n < 3; n++)
5118
{
5119
if (n > 0)
5120
ImGui::SameLine();
5121
5122
ImGui::PushID(n);
5123
ImGui::InvisibleButton("##canvas", size);
5124
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
5125
{
5126
offset.x += ImGui::GetIO().MouseDelta.x;
5127
offset.y += ImGui::GetIO().MouseDelta.y;
5128
}
5129
ImGui::PopID();
5130
if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
5131
continue;
5132
5133
const ImVec2 p0 = ImGui::GetItemRectMin();
5134
const ImVec2 p1 = ImGui::GetItemRectMax();
5135
const char* text_str = "Line 1 hello\nLine 2 clip me!";
5136
const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
5137
ImDrawList* draw_list = ImGui::GetWindowDrawList();
5138
switch (n)
5139
{
5140
case 0:
5141
ImGui::PushClipRect(p0, p1, true);
5142
draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
5143
draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
5144
ImGui::PopClipRect();
5145
break;
5146
case 1:
5147
draw_list->PushClipRect(p0, p1, true);
5148
draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
5149
draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
5150
draw_list->PopClipRect();
5151
break;
5152
case 2:
5153
ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
5154
draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
5155
draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImGui::GetFontWeight(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
5156
break;
5157
}
5158
}
5159
5160
ImGui::TreePop();
5161
}
5162
5163
IMGUI_DEMO_MARKER("Layout/Overlap Mode");
5164
if (ImGui::TreeNode("Overlap Mode"))
5165
{
5166
static bool enable_allow_overlap = true;
5167
5168
HelpMarker(
5169
"Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
5170
"By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
5171
"Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
5172
ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap);
5173
5174
ImVec2 button1_pos = ImGui::GetCursorScreenPos();
5175
ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
5176
if (enable_allow_overlap)
5177
ImGui::SetNextItemAllowOverlap();
5178
ImGui::Button("Button 1", ImVec2(80, 80));
5179
ImGui::SetCursorScreenPos(button2_pos);
5180
ImGui::Button("Button 2", ImVec2(80, 80));
5181
5182
// This is typically used with width-spanning items.
5183
// (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
5184
// for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
5185
if (enable_allow_overlap)
5186
ImGui::SetNextItemAllowOverlap();
5187
ImGui::Selectable("Some Selectable", false);
5188
ImGui::SameLine();
5189
ImGui::SmallButton("++");
5190
5191
ImGui::TreePop();
5192
}
5193
}
5194
5195
//-----------------------------------------------------------------------------
5196
// [SECTION] DemoWindowPopups()
5197
//-----------------------------------------------------------------------------
5198
5199
static void DemoWindowPopups()
5200
{
5201
IMGUI_DEMO_MARKER("Popups");
5202
if (!ImGui::CollapsingHeader("Popups & Modal windows"))
5203
return;
5204
5205
// The properties of popups windows are:
5206
// - They block normal mouse hovering detection outside them. (*)
5207
// - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
5208
// - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
5209
// we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
5210
// (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
5211
// when normally blocked by a popup.
5212
// Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
5213
// popups at any time.
5214
5215
// Typical use for regular windows:
5216
// 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();
5217
// Typical use for popups:
5218
// if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup")) { [...] EndPopup(); }
5219
5220
// With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
5221
// This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
5222
5223
IMGUI_DEMO_MARKER("Popups/Popups");
5224
if (ImGui::TreeNode("Popups"))
5225
{
5226
ImGui::TextWrapped(
5227
"When a popup is active, it inhibits interacting with windows that are behind the popup. "
5228
"Clicking outside the popup closes it.");
5229
5230
static int selected_fish = -1;
5231
const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
5232
static bool toggles[] = { true, false, false, false, false };
5233
5234
// Simple selection popup (if you want to show the current selection inside the Button itself,
5235
// you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
5236
if (ImGui::Button("Select.."))
5237
ImGui::OpenPopup("my_select_popup");
5238
ImGui::SameLine();
5239
ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
5240
if (ImGui::BeginPopup("my_select_popup"))
5241
{
5242
ImGui::SeparatorText("Aquarium");
5243
for (int i = 0; i < IM_COUNTOF(names); i++)
5244
if (ImGui::Selectable(names[i]))
5245
selected_fish = i;
5246
ImGui::EndPopup();
5247
}
5248
5249
// Showing a menu with toggles
5250
if (ImGui::Button("Toggle.."))
5251
ImGui::OpenPopup("my_toggle_popup");
5252
if (ImGui::BeginPopup("my_toggle_popup"))
5253
{
5254
for (int i = 0; i < IM_COUNTOF(names); i++)
5255
ImGui::MenuItem(names[i], "", &toggles[i]);
5256
if (ImGui::BeginMenu("Sub-menu"))
5257
{
5258
ImGui::MenuItem("Click me");
5259
ImGui::EndMenu();
5260
}
5261
5262
ImGui::Separator();
5263
ImGui::Text("Tooltip here");
5264
ImGui::SetItemTooltip("I am a tooltip over a popup");
5265
5266
if (ImGui::Button("Stacked Popup"))
5267
ImGui::OpenPopup("another popup");
5268
if (ImGui::BeginPopup("another popup"))
5269
{
5270
for (int i = 0; i < IM_COUNTOF(names); i++)
5271
ImGui::MenuItem(names[i], "", &toggles[i]);
5272
if (ImGui::BeginMenu("Sub-menu"))
5273
{
5274
ImGui::MenuItem("Click me");
5275
if (ImGui::Button("Stacked Popup"))
5276
ImGui::OpenPopup("another popup");
5277
if (ImGui::BeginPopup("another popup"))
5278
{
5279
ImGui::Text("I am the last one here.");
5280
ImGui::EndPopup();
5281
}
5282
ImGui::EndMenu();
5283
}
5284
ImGui::EndPopup();
5285
}
5286
ImGui::EndPopup();
5287
}
5288
5289
// Call the more complete ShowExampleMenuFile which we use in various places of this demo
5290
if (ImGui::Button("With a menu.."))
5291
ImGui::OpenPopup("my_file_popup");
5292
if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar))
5293
{
5294
if (ImGui::BeginMenuBar())
5295
{
5296
if (ImGui::BeginMenu("File"))
5297
{
5298
ShowExampleMenuFile();
5299
ImGui::EndMenu();
5300
}
5301
if (ImGui::BeginMenu("Edit"))
5302
{
5303
ImGui::MenuItem("Dummy");
5304
ImGui::EndMenu();
5305
}
5306
ImGui::EndMenuBar();
5307
}
5308
ImGui::Text("Hello from popup!");
5309
ImGui::Button("This is a dummy button..");
5310
ImGui::EndPopup();
5311
}
5312
5313
ImGui::TreePop();
5314
}
5315
5316
IMGUI_DEMO_MARKER("Popups/Context menus");
5317
if (ImGui::TreeNode("Context menus"))
5318
{
5319
HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
5320
5321
// BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
5322
// if (id == 0)
5323
// id = GetItemID(); // Use last item id
5324
// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
5325
// OpenPopup(id);
5326
// return BeginPopup(id);
5327
// For advanced uses you may want to replicate and customize this code.
5328
// See more details in BeginPopupContextItem().
5329
5330
// Example 1
5331
// When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
5332
// and BeginPopupContextItem() will use the last item ID as the popup ID.
5333
{
5334
const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
5335
static int selected = -1;
5336
for (int n = 0; n < 5; n++)
5337
{
5338
if (ImGui::Selectable(names[n], selected == n))
5339
selected = n;
5340
if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
5341
{
5342
selected = n;
5343
ImGui::Text("This is a popup for \"%s\"!", names[n]);
5344
if (ImGui::Button("Close"))
5345
ImGui::CloseCurrentPopup();
5346
ImGui::EndPopup();
5347
}
5348
ImGui::SetItemTooltip("Right-click to open popup");
5349
}
5350
}
5351
5352
// Example 2
5353
// Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
5354
// Using an explicit identifier is also convenient if you want to activate the popups from different locations.
5355
{
5356
HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
5357
static float value = 0.5f;
5358
ImGui::Text("Value = %.3f <-- (1) right-click this text", value);
5359
if (ImGui::BeginPopupContextItem("my popup"))
5360
{
5361
if (ImGui::Selectable("Set to zero")) value = 0.0f;
5362
if (ImGui::Selectable("Set to PI")) value = 3.1415f;
5363
ImGui::SetNextItemWidth(-FLT_MIN);
5364
ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
5365
ImGui::EndPopup();
5366
}
5367
5368
// We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
5369
// Here we make it that right-clicking this other text element opens the same popup as above.
5370
// The popup itself will be submitted by the code above.
5371
ImGui::Text("(2) Or right-click this text");
5372
ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
5373
5374
// Back to square one: manually open the same popup.
5375
if (ImGui::Button("(3) Or click this button"))
5376
ImGui::OpenPopup("my popup");
5377
}
5378
5379
// Example 3
5380
// When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
5381
// we need to make sure your item identifier is stable.
5382
// In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
5383
{
5384
HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
5385
static char name[32] = "Label1";
5386
char buf[64];
5387
sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
5388
ImGui::Button(buf);
5389
if (ImGui::BeginPopupContextItem())
5390
{
5391
ImGui::Text("Edit name:");
5392
ImGui::InputText("##edit", name, IM_COUNTOF(name));
5393
if (ImGui::Button("Close"))
5394
ImGui::CloseCurrentPopup();
5395
ImGui::EndPopup();
5396
}
5397
ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
5398
}
5399
5400
ImGui::TreePop();
5401
}
5402
5403
IMGUI_DEMO_MARKER("Popups/Modals");
5404
if (ImGui::TreeNode("Modals"))
5405
{
5406
ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
5407
5408
if (ImGui::Button("Delete.."))
5409
ImGui::OpenPopup("Delete?");
5410
5411
// Always center this window when appearing
5412
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
5413
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
5414
5415
if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
5416
{
5417
ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
5418
ImGui::Separator();
5419
5420
//static int unused_i = 0;
5421
//ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
5422
5423
static bool dont_ask_me_next_time = false;
5424
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
5425
ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
5426
ImGui::PopStyleVar();
5427
5428
if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5429
ImGui::SetItemDefaultFocus();
5430
ImGui::SameLine();
5431
if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5432
ImGui::EndPopup();
5433
}
5434
5435
if (ImGui::Button("Stacked modals.."))
5436
ImGui::OpenPopup("Stacked 1");
5437
if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
5438
{
5439
if (ImGui::BeginMenuBar())
5440
{
5441
if (ImGui::BeginMenu("File"))
5442
{
5443
if (ImGui::MenuItem("Some menu item")) {}
5444
ImGui::EndMenu();
5445
}
5446
ImGui::EndMenuBar();
5447
}
5448
ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
5449
5450
// Testing behavior of widgets stacking their own regular popups over the modal.
5451
static int item = 1;
5452
static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
5453
ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
5454
ImGui::ColorEdit4("Color", color);
5455
5456
if (ImGui::Button("Add another modal.."))
5457
ImGui::OpenPopup("Stacked 2");
5458
5459
// Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
5460
// will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
5461
// of the bool actually doesn't matter here.
5462
bool unused_open = true;
5463
if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
5464
{
5465
ImGui::Text("Hello from Stacked The Second!");
5466
ImGui::ColorEdit4("Color", color); // Allow opening another nested popup
5467
if (ImGui::Button("Close"))
5468
ImGui::CloseCurrentPopup();
5469
ImGui::EndPopup();
5470
}
5471
5472
if (ImGui::Button("Close"))
5473
ImGui::CloseCurrentPopup();
5474
ImGui::EndPopup();
5475
}
5476
5477
ImGui::TreePop();
5478
}
5479
5480
IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
5481
if (ImGui::TreeNode("Menus inside a regular window"))
5482
{
5483
ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
5484
ImGui::Separator();
5485
5486
ImGui::MenuItem("Menu item", "Ctrl+M");
5487
if (ImGui::BeginMenu("Menu inside a regular window"))
5488
{
5489
ShowExampleMenuFile();
5490
ImGui::EndMenu();
5491
}
5492
ImGui::Separator();
5493
ImGui::TreePop();
5494
}
5495
}
5496
5497
// Dummy data structure that we use for the Table demo.
5498
// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
5499
namespace
5500
{
5501
// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
5502
// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
5503
// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
5504
// If you don't use sorting, you will generally never care about giving column an ID!
5505
enum MyItemColumnID
5506
{
5507
MyItemColumnID_ID,
5508
MyItemColumnID_Name,
5509
MyItemColumnID_Action,
5510
MyItemColumnID_Quantity,
5511
MyItemColumnID_Description
5512
};
5513
5514
struct MyItem
5515
{
5516
int ID;
5517
const char* Name;
5518
int Quantity;
5519
5520
// We have a problem which is affecting _only this demo_ and should not affect your code:
5521
// As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
5522
// however qsort doesn't allow passing user data to comparing function.
5523
// As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
5524
// In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
5525
// We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
5526
// very often by the sorting algorithm it would be a little wasteful.
5527
static const ImGuiTableSortSpecs* s_current_sort_specs;
5528
5529
static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
5530
{
5531
s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
5532
if (items_count > 1)
5533
qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
5534
s_current_sort_specs = NULL;
5535
}
5536
5537
// Compare function to be used by qsort()
5538
static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
5539
{
5540
const MyItem* a = (const MyItem*)lhs;
5541
const MyItem* b = (const MyItem*)rhs;
5542
for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
5543
{
5544
// Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
5545
// We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
5546
const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
5547
int delta = 0;
5548
switch (sort_spec->ColumnUserID)
5549
{
5550
case MyItemColumnID_ID: delta = (a->ID - b->ID); break;
5551
case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break;
5552
case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break;
5553
case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break;
5554
default: IM_ASSERT(0); break;
5555
}
5556
if (delta > 0)
5557
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
5558
if (delta < 0)
5559
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
5560
}
5561
5562
// qsort() is instable so always return a way to differentiate items.
5563
// Your own compare function may want to avoid fallback on implicit sort specs.
5564
// e.g. a Name compare if it wasn't already part of the sort specs.
5565
return a->ID - b->ID;
5566
}
5567
};
5568
const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
5569
}
5570
5571
// Make the UI compact because there are so many fields
5572
static void PushStyleCompact()
5573
{
5574
ImGuiStyle& style = ImGui::GetStyle();
5575
ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f));
5576
ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f));
5577
}
5578
5579
static void PopStyleCompact()
5580
{
5581
ImGui::PopStyleVar(2);
5582
}
5583
5584
// Show a combo box with a choice of sizing policies
5585
static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
5586
{
5587
struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
5588
static const EnumDesc policies[] =
5589
{
5590
{ 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." },
5591
{ ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
5592
{ ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
5593
{ ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
5594
{ ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
5595
};
5596
int idx;
5597
for (idx = 0; idx < IM_COUNTOF(policies); idx++)
5598
if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
5599
break;
5600
const char* preview_text = (idx < IM_COUNTOF(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
5601
if (ImGui::BeginCombo("Sizing Policy", preview_text))
5602
{
5603
for (int n = 0; n < IM_COUNTOF(policies); n++)
5604
if (ImGui::Selectable(policies[n].Name, idx == n))
5605
*p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
5606
ImGui::EndCombo();
5607
}
5608
ImGui::SameLine();
5609
ImGui::TextDisabled("(?)");
5610
if (ImGui::BeginItemTooltip())
5611
{
5612
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
5613
for (int m = 0; m < IM_COUNTOF(policies); m++)
5614
{
5615
ImGui::Separator();
5616
ImGui::Text("%s:", policies[m].Name);
5617
ImGui::Separator();
5618
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
5619
ImGui::TextUnformatted(policies[m].Tooltip);
5620
}
5621
ImGui::PopTextWrapPos();
5622
ImGui::EndTooltip();
5623
}
5624
}
5625
5626
static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
5627
{
5628
ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
5629
ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
5630
ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
5631
if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
5632
*p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
5633
if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
5634
*p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
5635
ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
5636
ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
5637
ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
5638
ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
5639
ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
5640
ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
5641
ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
5642
ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
5643
ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
5644
ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
5645
ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
5646
ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
5647
ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
5648
ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
5649
}
5650
5651
static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
5652
{
5653
ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
5654
ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
5655
ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
5656
ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
5657
}
5658
5659
//-----------------------------------------------------------------------------
5660
// [SECTION] DemoWindowTables()
5661
//-----------------------------------------------------------------------------
5662
5663
static void DemoWindowTables()
5664
{
5665
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
5666
IMGUI_DEMO_MARKER("Tables");
5667
if (!ImGui::CollapsingHeader("Tables & Columns"))
5668
return;
5669
5670
// Using those as a base value to create width/height that are factor of the size of our font
5671
const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
5672
const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
5673
5674
ImGui::PushID("Tables");
5675
5676
int open_action = -1;
5677
if (ImGui::Button("Expand all"))
5678
open_action = 1;
5679
ImGui::SameLine();
5680
if (ImGui::Button("Collapse all"))
5681
open_action = 0;
5682
ImGui::SameLine();
5683
5684
// Options
5685
static bool disable_indent = false;
5686
ImGui::Checkbox("Disable tree indentation", &disable_indent);
5687
ImGui::SameLine();
5688
HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
5689
ImGui::Separator();
5690
if (disable_indent)
5691
ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
5692
5693
// About Styling of tables
5694
// Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
5695
// There are however a few settings that a shared and part of the ImGuiStyle structure:
5696
// style.CellPadding // Padding within each cell
5697
// style.Colors[ImGuiCol_TableHeaderBg] // Table header background
5698
// style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders
5699
// style.Colors[ImGuiCol_TableBorderLight] // Table inner borders
5700
// style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
5701
// style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
5702
5703
// Demos
5704
if (open_action != -1)
5705
ImGui::SetNextItemOpen(open_action != 0);
5706
IMGUI_DEMO_MARKER("Tables/Basic");
5707
if (ImGui::TreeNode("Basic"))
5708
{
5709
// Here we will showcase three different ways to output a table.
5710
// They are very simple variations of a same thing!
5711
5712
// [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
5713
// In many situations, this is the most flexible and easy to use pattern.
5714
HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
5715
if (ImGui::BeginTable("table1", 3))
5716
{
5717
for (int row = 0; row < 4; row++)
5718
{
5719
ImGui::TableNextRow();
5720
for (int column = 0; column < 3; column++)
5721
{
5722
ImGui::TableSetColumnIndex(column);
5723
ImGui::Text("Row %d Column %d", row, column);
5724
}
5725
}
5726
ImGui::EndTable();
5727
}
5728
5729
// [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
5730
// This is generally more convenient when you have code manually submitting the contents of each column.
5731
HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
5732
if (ImGui::BeginTable("table2", 3))
5733
{
5734
for (int row = 0; row < 4; row++)
5735
{
5736
ImGui::TableNextRow();
5737
ImGui::TableNextColumn();
5738
ImGui::Text("Row %d", row);
5739
ImGui::TableNextColumn();
5740
ImGui::Text("Some contents");
5741
ImGui::TableNextColumn();
5742
ImGui::Text("123.456");
5743
}
5744
ImGui::EndTable();
5745
}
5746
5747
// [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
5748
// as TableNextColumn() will automatically wrap around and create new rows as needed.
5749
// This is generally more convenient when your cells all contains the same type of data.
5750
HelpMarker(
5751
"Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
5752
"the same type of contents.\n This is also more similar to the old NextColumn() function of the "
5753
"Columns API, and provided to facilitate the Columns->Tables API transition.");
5754
if (ImGui::BeginTable("table3", 3))
5755
{
5756
for (int item = 0; item < 14; item++)
5757
{
5758
ImGui::TableNextColumn();
5759
ImGui::Text("Item %d", item);
5760
}
5761
ImGui::EndTable();
5762
}
5763
5764
ImGui::TreePop();
5765
}
5766
5767
if (open_action != -1)
5768
ImGui::SetNextItemOpen(open_action != 0);
5769
IMGUI_DEMO_MARKER("Tables/Borders, background");
5770
if (ImGui::TreeNode("Borders, background"))
5771
{
5772
// Expose a few Borders related flags interactively
5773
enum ContentsType { CT_Text, CT_FillButton };
5774
static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5775
static bool display_headers = false;
5776
static int contents_type = CT_Text;
5777
5778
PushStyleCompact();
5779
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5780
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
5781
ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH");
5782
ImGui::Indent();
5783
5784
ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
5785
ImGui::Indent();
5786
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
5787
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
5788
ImGui::Unindent();
5789
5790
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5791
ImGui::Indent();
5792
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
5793
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
5794
ImGui::Unindent();
5795
5796
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
5797
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
5798
ImGui::Unindent();
5799
5800
ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
5801
ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
5802
ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
5803
ImGui::Checkbox("Display headers", &display_headers);
5804
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)");
5805
PopStyleCompact();
5806
5807
if (ImGui::BeginTable("table1", 3, flags))
5808
{
5809
// Display headers so we can inspect their interaction with borders
5810
// (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)
5811
if (display_headers)
5812
{
5813
ImGui::TableSetupColumn("One");
5814
ImGui::TableSetupColumn("Two");
5815
ImGui::TableSetupColumn("Three");
5816
ImGui::TableHeadersRow();
5817
}
5818
5819
for (int row = 0; row < 5; row++)
5820
{
5821
ImGui::TableNextRow();
5822
for (int column = 0; column < 3; column++)
5823
{
5824
ImGui::TableSetColumnIndex(column);
5825
char buf[32];
5826
sprintf(buf, "Hello %d,%d", column, row);
5827
if (contents_type == CT_Text)
5828
ImGui::TextUnformatted(buf);
5829
else if (contents_type == CT_FillButton)
5830
ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5831
}
5832
}
5833
ImGui::EndTable();
5834
}
5835
ImGui::TreePop();
5836
}
5837
5838
if (open_action != -1)
5839
ImGui::SetNextItemOpen(open_action != 0);
5840
IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
5841
if (ImGui::TreeNode("Resizable, stretch"))
5842
{
5843
// By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
5844
// All columns maintain a sizing weight, and they will occupy all available width.
5845
static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5846
PushStyleCompact();
5847
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5848
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5849
ImGui::SameLine(); HelpMarker(
5850
"Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
5851
"this is why the resize borders are still showing when unchecking this.");
5852
PopStyleCompact();
5853
5854
if (ImGui::BeginTable("table1", 3, flags))
5855
{
5856
for (int row = 0; row < 5; row++)
5857
{
5858
ImGui::TableNextRow();
5859
for (int column = 0; column < 3; column++)
5860
{
5861
ImGui::TableSetColumnIndex(column);
5862
ImGui::Text("Hello %d,%d", column, row);
5863
}
5864
}
5865
ImGui::EndTable();
5866
}
5867
ImGui::TreePop();
5868
}
5869
5870
if (open_action != -1)
5871
ImGui::SetNextItemOpen(open_action != 0);
5872
IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
5873
if (ImGui::TreeNode("Resizable, fixed"))
5874
{
5875
// Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
5876
// So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
5877
// If there is not enough available width to fit all columns, they will however be resized down.
5878
// FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
5879
HelpMarker(
5880
"Using _Resizable + _SizingFixedFit flags.\n"
5881
"Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
5882
"Double-click a column border to auto-fit the column to its contents.");
5883
PushStyleCompact();
5884
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5885
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5886
PopStyleCompact();
5887
5888
if (ImGui::BeginTable("table1", 3, flags))
5889
{
5890
for (int row = 0; row < 5; row++)
5891
{
5892
ImGui::TableNextRow();
5893
for (int column = 0; column < 3; column++)
5894
{
5895
ImGui::TableSetColumnIndex(column);
5896
ImGui::Text("Hello %d,%d", column, row);
5897
}
5898
}
5899
ImGui::EndTable();
5900
}
5901
ImGui::TreePop();
5902
}
5903
5904
if (open_action != -1)
5905
ImGui::SetNextItemOpen(open_action != 0);
5906
IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
5907
if (ImGui::TreeNode("Resizable, mixed"))
5908
{
5909
HelpMarker(
5910
"Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
5911
"When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
5912
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5913
5914
if (ImGui::BeginTable("table1", 3, flags))
5915
{
5916
ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5917
ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5918
ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
5919
ImGui::TableHeadersRow();
5920
for (int row = 0; row < 5; row++)
5921
{
5922
ImGui::TableNextRow();
5923
for (int column = 0; column < 3; column++)
5924
{
5925
ImGui::TableSetColumnIndex(column);
5926
ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
5927
}
5928
}
5929
ImGui::EndTable();
5930
}
5931
if (ImGui::BeginTable("table2", 6, flags))
5932
{
5933
ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5934
ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5935
ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
5936
ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
5937
ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
5938
ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
5939
ImGui::TableHeadersRow();
5940
for (int row = 0; row < 5; row++)
5941
{
5942
ImGui::TableNextRow();
5943
for (int column = 0; column < 6; column++)
5944
{
5945
ImGui::TableSetColumnIndex(column);
5946
ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
5947
}
5948
}
5949
ImGui::EndTable();
5950
}
5951
ImGui::TreePop();
5952
}
5953
5954
if (open_action != -1)
5955
ImGui::SetNextItemOpen(open_action != 0);
5956
IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
5957
if (ImGui::TreeNode("Reorderable, hideable, with headers"))
5958
{
5959
HelpMarker(
5960
"Click and drag column headers to reorder columns.\n\n"
5961
"Right-click on a header to open a context menu.");
5962
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
5963
PushStyleCompact();
5964
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5965
ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
5966
ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
5967
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
5968
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)");
5969
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5970
PopStyleCompact();
5971
5972
if (ImGui::BeginTable("table1", 3, flags))
5973
{
5974
// Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
5975
// (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
5976
ImGui::TableSetupColumn("One");
5977
ImGui::TableSetupColumn("Two");
5978
ImGui::TableSetupColumn("Three");
5979
ImGui::TableHeadersRow();
5980
for (int row = 0; row < 6; row++)
5981
{
5982
ImGui::TableNextRow();
5983
for (int column = 0; column < 3; column++)
5984
{
5985
ImGui::TableSetColumnIndex(column);
5986
ImGui::Text("Hello %d,%d", column, row);
5987
}
5988
}
5989
ImGui::EndTable();
5990
}
5991
5992
// Use outer_size.x == 0.0f instead of default to make the table as tight as possible
5993
// (only valid when no scrolling and no stretch column)
5994
if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
5995
{
5996
ImGui::TableSetupColumn("One");
5997
ImGui::TableSetupColumn("Two");
5998
ImGui::TableSetupColumn("Three");
5999
ImGui::TableHeadersRow();
6000
for (int row = 0; row < 6; row++)
6001
{
6002
ImGui::TableNextRow();
6003
for (int column = 0; column < 3; column++)
6004
{
6005
ImGui::TableSetColumnIndex(column);
6006
ImGui::Text("Fixed %d,%d", column, row);
6007
}
6008
}
6009
ImGui::EndTable();
6010
}
6011
ImGui::TreePop();
6012
}
6013
6014
if (open_action != -1)
6015
ImGui::SetNextItemOpen(open_action != 0);
6016
IMGUI_DEMO_MARKER("Tables/Padding");
6017
if (ImGui::TreeNode("Padding"))
6018
{
6019
// First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
6020
// We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
6021
HelpMarker(
6022
"We often want outer padding activated when any using features which makes the edges of a column visible:\n"
6023
"e.g.:\n"
6024
"- BorderOuterV\n"
6025
"- any form of row selection\n"
6026
"Because of this, activating BorderOuterV sets the default to PadOuterX. "
6027
"Using PadOuterX or NoPadOuterX you can override the default.\n\n"
6028
"Actual padding values are using style.CellPadding.\n\n"
6029
"In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
6030
6031
static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
6032
PushStyleCompact();
6033
ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
6034
ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
6035
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
6036
ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
6037
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
6038
ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
6039
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
6040
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
6041
static bool show_headers = false;
6042
ImGui::Checkbox("show_headers", &show_headers);
6043
PopStyleCompact();
6044
6045
if (ImGui::BeginTable("table_padding", 3, flags1))
6046
{
6047
if (show_headers)
6048
{
6049
ImGui::TableSetupColumn("One");
6050
ImGui::TableSetupColumn("Two");
6051
ImGui::TableSetupColumn("Three");
6052
ImGui::TableHeadersRow();
6053
}
6054
6055
for (int row = 0; row < 5; row++)
6056
{
6057
ImGui::TableNextRow();
6058
for (int column = 0; column < 3; column++)
6059
{
6060
ImGui::TableSetColumnIndex(column);
6061
if (row == 0)
6062
{
6063
ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
6064
}
6065
else
6066
{
6067
char buf[32];
6068
sprintf(buf, "Hello %d,%d", column, row);
6069
ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
6070
}
6071
//if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
6072
// ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
6073
}
6074
}
6075
ImGui::EndTable();
6076
}
6077
6078
// Second example: set style.CellPadding to (0.0) or a custom value.
6079
// FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
6080
HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
6081
static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
6082
static ImVec2 cell_padding(0.0f, 0.0f);
6083
static bool show_widget_frame_bg = true;
6084
6085
PushStyleCompact();
6086
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
6087
ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
6088
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
6089
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
6090
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
6091
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
6092
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
6093
ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
6094
ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
6095
PopStyleCompact();
6096
6097
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
6098
if (ImGui::BeginTable("table_padding_2", 3, flags2))
6099
{
6100
static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
6101
static bool init = true;
6102
if (!show_widget_frame_bg)
6103
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
6104
for (int cell = 0; cell < 3 * 5; cell++)
6105
{
6106
ImGui::TableNextColumn();
6107
if (init)
6108
strcpy(text_bufs[cell], "edit me");
6109
ImGui::SetNextItemWidth(-FLT_MIN);
6110
ImGui::PushID(cell);
6111
ImGui::InputText("##cell", text_bufs[cell], IM_COUNTOF(text_bufs[cell]));
6112
ImGui::PopID();
6113
}
6114
if (!show_widget_frame_bg)
6115
ImGui::PopStyleColor();
6116
init = false;
6117
ImGui::EndTable();
6118
}
6119
ImGui::PopStyleVar();
6120
6121
ImGui::TreePop();
6122
}
6123
6124
if (open_action != -1)
6125
ImGui::SetNextItemOpen(open_action != 0);
6126
IMGUI_DEMO_MARKER("Tables/Explicit widths");
6127
if (ImGui::TreeNode("Sizing policies"))
6128
{
6129
static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
6130
PushStyleCompact();
6131
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6132
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
6133
PopStyleCompact();
6134
6135
static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
6136
for (int table_n = 0; table_n < 4; table_n++)
6137
{
6138
ImGui::PushID(table_n);
6139
ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
6140
EditTableSizingFlags(&sizing_policy_flags[table_n]);
6141
6142
// To make it easier to understand the different sizing policy,
6143
// For each policy: we display one table where the columns have equal contents width,
6144
// and one where the columns have different contents width.
6145
if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
6146
{
6147
for (int row = 0; row < 3; row++)
6148
{
6149
ImGui::TableNextRow();
6150
ImGui::TableNextColumn(); ImGui::Text("Oh dear");
6151
ImGui::TableNextColumn(); ImGui::Text("Oh dear");
6152
ImGui::TableNextColumn(); ImGui::Text("Oh dear");
6153
}
6154
ImGui::EndTable();
6155
}
6156
if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
6157
{
6158
for (int row = 0; row < 3; row++)
6159
{
6160
ImGui::TableNextRow();
6161
ImGui::TableNextColumn(); ImGui::Text("AAAA");
6162
ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
6163
ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
6164
}
6165
ImGui::EndTable();
6166
}
6167
ImGui::PopID();
6168
}
6169
6170
ImGui::Spacing();
6171
ImGui::TextUnformatted("Advanced");
6172
ImGui::SameLine();
6173
HelpMarker(
6174
"This section allows you to interact and see the effect of various sizing policies "
6175
"depending on whether Scroll is enabled and the contents of your columns.");
6176
6177
enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
6178
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
6179
static int contents_type = CT_ShowWidth;
6180
static int column_count = 3;
6181
6182
PushStyleCompact();
6183
ImGui::PushID("Advanced");
6184
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
6185
EditTableSizingFlags(&flags);
6186
ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
6187
if (contents_type == CT_FillButton)
6188
{
6189
ImGui::SameLine();
6190
HelpMarker(
6191
"Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
6192
"where contents width can feed into auto-column width can feed into contents width.");
6193
}
6194
ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
6195
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6196
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
6197
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.");
6198
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6199
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6200
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
6201
ImGui::PopItemWidth();
6202
ImGui::PopID();
6203
PopStyleCompact();
6204
6205
if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
6206
{
6207
for (int cell = 0; cell < 10 * column_count; cell++)
6208
{
6209
ImGui::TableNextColumn();
6210
int column = ImGui::TableGetColumnIndex();
6211
int row = ImGui::TableGetRowIndex();
6212
6213
ImGui::PushID(cell);
6214
char label[32];
6215
static char text_buf[32] = "";
6216
sprintf(label, "Hello %d,%d", column, row);
6217
switch (contents_type)
6218
{
6219
case CT_ShortText: ImGui::TextUnformatted(label); break;
6220
case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
6221
case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
6222
case CT_Button: ImGui::Button(label); break;
6223
case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
6224
case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_COUNTOF(text_buf)); break;
6225
}
6226
ImGui::PopID();
6227
}
6228
ImGui::EndTable();
6229
}
6230
ImGui::TreePop();
6231
}
6232
6233
if (open_action != -1)
6234
ImGui::SetNextItemOpen(open_action != 0);
6235
IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
6236
if (ImGui::TreeNode("Vertical scrolling, with clipping"))
6237
{
6238
HelpMarker(
6239
"Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
6240
"We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
6241
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
6242
6243
PushStyleCompact();
6244
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6245
PopStyleCompact();
6246
6247
// When using ScrollX or ScrollY we need to specify a size for our table container!
6248
// Otherwise by default the table will fit all available space, like a BeginChild() call.
6249
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
6250
if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
6251
{
6252
ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
6253
ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
6254
ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
6255
ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
6256
ImGui::TableHeadersRow();
6257
6258
// Demonstrate using clipper for large vertical lists
6259
ImGuiListClipper clipper;
6260
clipper.Begin(1000);
6261
while (clipper.Step())
6262
{
6263
for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
6264
{
6265
ImGui::TableNextRow();
6266
for (int column = 0; column < 3; column++)
6267
{
6268
ImGui::TableSetColumnIndex(column);
6269
ImGui::Text("Hello %d,%d", column, row);
6270
}
6271
}
6272
}
6273
ImGui::EndTable();
6274
}
6275
ImGui::TreePop();
6276
}
6277
6278
if (open_action != -1)
6279
ImGui::SetNextItemOpen(open_action != 0);
6280
IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
6281
if (ImGui::TreeNode("Horizontal scrolling"))
6282
{
6283
HelpMarker(
6284
"When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
6285
"as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
6286
"Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
6287
"because the container window won't automatically extend vertically to fix contents "
6288
"(this may be improved in future versions).");
6289
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
6290
static int freeze_cols = 1;
6291
static int freeze_rows = 1;
6292
6293
PushStyleCompact();
6294
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6295
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6296
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6297
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6298
ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6299
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6300
ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6301
PopStyleCompact();
6302
6303
// When using ScrollX or ScrollY we need to specify a size for our table container!
6304
// Otherwise by default the table will fit all available space, like a BeginChild() call.
6305
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
6306
if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
6307
{
6308
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
6309
ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
6310
ImGui::TableSetupColumn("One");
6311
ImGui::TableSetupColumn("Two");
6312
ImGui::TableSetupColumn("Three");
6313
ImGui::TableSetupColumn("Four");
6314
ImGui::TableSetupColumn("Five");
6315
ImGui::TableSetupColumn("Six");
6316
ImGui::TableHeadersRow();
6317
for (int row = 0; row < 20; row++)
6318
{
6319
ImGui::TableNextRow();
6320
for (int column = 0; column < 7; column++)
6321
{
6322
// Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
6323
// Because here we know that:
6324
// - A) all our columns are contributing the same to row height
6325
// - B) column 0 is always visible,
6326
// We only always submit this one column and can skip others.
6327
// More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
6328
if (!ImGui::TableSetColumnIndex(column) && column > 0)
6329
continue;
6330
if (column == 0)
6331
ImGui::Text("Line %d", row);
6332
else
6333
ImGui::Text("Hello world %d,%d", column, row);
6334
}
6335
}
6336
ImGui::EndTable();
6337
}
6338
6339
ImGui::Spacing();
6340
ImGui::TextUnformatted("Stretch + ScrollX");
6341
ImGui::SameLine();
6342
HelpMarker(
6343
"Showcase using Stretch columns + ScrollX together: "
6344
"this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
6345
"Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
6346
"along with ScrollX doesn't make sense.");
6347
static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
6348
static float inner_width = 1000.0f;
6349
PushStyleCompact();
6350
ImGui::PushID("flags3");
6351
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
6352
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
6353
ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
6354
ImGui::PopItemWidth();
6355
ImGui::PopID();
6356
PopStyleCompact();
6357
if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
6358
{
6359
for (int cell = 0; cell < 20 * 7; cell++)
6360
{
6361
ImGui::TableNextColumn();
6362
ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
6363
}
6364
ImGui::EndTable();
6365
}
6366
ImGui::TreePop();
6367
}
6368
6369
if (open_action != -1)
6370
ImGui::SetNextItemOpen(open_action != 0);
6371
IMGUI_DEMO_MARKER("Tables/Columns flags");
6372
if (ImGui::TreeNode("Columns flags"))
6373
{
6374
// Create a first table just to show all the options/flags we want to make visible in our example!
6375
const int column_count = 3;
6376
const char* column_names[column_count] = { "One", "Two", "Three" };
6377
static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
6378
static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
6379
6380
if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
6381
{
6382
PushStyleCompact();
6383
for (int column = 0; column < column_count; column++)
6384
{
6385
ImGui::TableNextColumn();
6386
ImGui::PushID(column);
6387
ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
6388
ImGui::Text("'%s'", column_names[column]);
6389
ImGui::Spacing();
6390
ImGui::Text("Input flags:");
6391
EditTableColumnsFlags(&column_flags[column]);
6392
ImGui::Spacing();
6393
ImGui::Text("Output flags:");
6394
ImGui::BeginDisabled();
6395
ShowTableColumnsStatusFlags(column_flags_out[column]);
6396
ImGui::EndDisabled();
6397
ImGui::PopID();
6398
}
6399
PopStyleCompact();
6400
ImGui::EndTable();
6401
}
6402
6403
// Create the real table we care about for the example!
6404
// We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
6405
// otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
6406
// + resizing the parent window down).
6407
const ImGuiTableFlags flags
6408
= ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6409
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
6410
| ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
6411
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
6412
if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
6413
{
6414
bool has_angled_header = false;
6415
for (int column = 0; column < column_count; column++)
6416
{
6417
has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
6418
ImGui::TableSetupColumn(column_names[column], column_flags[column]);
6419
}
6420
if (has_angled_header)
6421
ImGui::TableAngledHeadersRow();
6422
ImGui::TableHeadersRow();
6423
for (int column = 0; column < column_count; column++)
6424
column_flags_out[column] = ImGui::TableGetColumnFlags(column);
6425
float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
6426
for (int row = 0; row < 8; row++)
6427
{
6428
// Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
6429
ImGui::Indent(indent_step);
6430
ImGui::TableNextRow();
6431
for (int column = 0; column < column_count; column++)
6432
{
6433
ImGui::TableSetColumnIndex(column);
6434
ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
6435
}
6436
}
6437
ImGui::Unindent(indent_step * 8.0f);
6438
6439
ImGui::EndTable();
6440
}
6441
ImGui::TreePop();
6442
}
6443
6444
if (open_action != -1)
6445
ImGui::SetNextItemOpen(open_action != 0);
6446
IMGUI_DEMO_MARKER("Tables/Columns widths");
6447
if (ImGui::TreeNode("Columns widths"))
6448
{
6449
HelpMarker("Using TableSetupColumn() to setup default width.");
6450
6451
static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
6452
PushStyleCompact();
6453
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6454
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
6455
PopStyleCompact();
6456
if (ImGui::BeginTable("table1", 3, flags1))
6457
{
6458
// We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
6459
ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
6460
ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
6461
ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto
6462
ImGui::TableHeadersRow();
6463
for (int row = 0; row < 4; row++)
6464
{
6465
ImGui::TableNextRow();
6466
for (int column = 0; column < 3; column++)
6467
{
6468
ImGui::TableSetColumnIndex(column);
6469
if (row == 0)
6470
ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6471
else
6472
ImGui::Text("Hello %d,%d", column, row);
6473
}
6474
}
6475
ImGui::EndTable();
6476
}
6477
6478
HelpMarker(
6479
"Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
6480
"fixed columns with set width may still be shrunk down if there's not enough space in the host.");
6481
6482
static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
6483
PushStyleCompact();
6484
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
6485
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
6486
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
6487
PopStyleCompact();
6488
if (ImGui::BeginTable("table2", 4, flags2))
6489
{
6490
// We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
6491
// will default to ImGuiTableColumnFlags_WidthFixed.
6492
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
6493
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6494
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
6495
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6496
for (int row = 0; row < 5; row++)
6497
{
6498
ImGui::TableNextRow();
6499
for (int column = 0; column < 4; column++)
6500
{
6501
ImGui::TableSetColumnIndex(column);
6502
if (row == 0)
6503
ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6504
else
6505
ImGui::Text("Hello %d,%d", column, row);
6506
}
6507
}
6508
ImGui::EndTable();
6509
}
6510
ImGui::TreePop();
6511
}
6512
6513
if (open_action != -1)
6514
ImGui::SetNextItemOpen(open_action != 0);
6515
IMGUI_DEMO_MARKER("Tables/Nested tables");
6516
if (ImGui::TreeNode("Nested tables"))
6517
{
6518
HelpMarker("This demonstrates embedding a table into another table cell.");
6519
6520
if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6521
{
6522
ImGui::TableSetupColumn("A0");
6523
ImGui::TableSetupColumn("A1");
6524
ImGui::TableHeadersRow();
6525
6526
ImGui::TableNextColumn();
6527
ImGui::Text("A0 Row 0");
6528
{
6529
float rows_height = (TEXT_BASE_HEIGHT * 2.0f) + (ImGui::GetStyle().CellPadding.y * 2.0f);
6530
if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6531
{
6532
ImGui::TableSetupColumn("B0");
6533
ImGui::TableSetupColumn("B1");
6534
ImGui::TableHeadersRow();
6535
6536
ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6537
ImGui::TableNextColumn();
6538
ImGui::Text("B0 Row 0");
6539
ImGui::TableNextColumn();
6540
ImGui::Text("B1 Row 0");
6541
ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6542
ImGui::TableNextColumn();
6543
ImGui::Text("B0 Row 1");
6544
ImGui::TableNextColumn();
6545
ImGui::Text("B1 Row 1");
6546
6547
ImGui::EndTable();
6548
}
6549
}
6550
ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
6551
ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
6552
ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
6553
ImGui::EndTable();
6554
}
6555
ImGui::TreePop();
6556
}
6557
6558
if (open_action != -1)
6559
ImGui::SetNextItemOpen(open_action != 0);
6560
IMGUI_DEMO_MARKER("Tables/Row height");
6561
if (ImGui::TreeNode("Row height"))
6562
{
6563
HelpMarker(
6564
"You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
6565
"so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
6566
"We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
6567
if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
6568
{
6569
for (int row = 0; row < 8; row++)
6570
{
6571
float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row + ImGui::GetStyle().CellPadding.y * 2.0f);
6572
ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
6573
ImGui::TableNextColumn();
6574
ImGui::Text("min_row_height = %.2f", min_row_height);
6575
}
6576
ImGui::EndTable();
6577
}
6578
6579
HelpMarker(
6580
"Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
6581
"Please note that Tables Row Height is not the same thing as Current Line Height, "
6582
"as a table cell may contains multiple lines.");
6583
if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
6584
{
6585
ImGui::TableNextRow();
6586
ImGui::TableNextColumn();
6587
ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6588
ImGui::TableNextColumn();
6589
ImGui::Text("Line 1");
6590
ImGui::Text("Line 2");
6591
6592
ImGui::TableNextRow();
6593
ImGui::TableNextColumn();
6594
ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6595
ImGui::TableNextColumn();
6596
ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
6597
ImGui::Text("Line 1, with SameLine(0,0)");
6598
ImGui::Text("Line 2");
6599
6600
ImGui::EndTable();
6601
}
6602
6603
HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
6604
if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
6605
{
6606
ImGuiStyle& style = ImGui::GetStyle();
6607
for (int row = 0; row < 8; row++)
6608
{
6609
if ((row % 3) == 2)
6610
ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f);
6611
ImGui::TableNextRow(ImGuiTableRowFlags_None);
6612
ImGui::TableNextColumn();
6613
ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
6614
if ((row % 3) == 2)
6615
ImGui::PopStyleVar();
6616
}
6617
ImGui::EndTable();
6618
}
6619
6620
ImGui::TreePop();
6621
}
6622
6623
if (open_action != -1)
6624
ImGui::SetNextItemOpen(open_action != 0);
6625
IMGUI_DEMO_MARKER("Tables/Outer size");
6626
if (ImGui::TreeNode("Outer size"))
6627
{
6628
// Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
6629
// Important to that note how the two flags have slightly different behaviors!
6630
ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
6631
PushStyleCompact();
6632
static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
6633
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6634
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.");
6635
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6636
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.");
6637
PopStyleCompact();
6638
6639
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
6640
if (ImGui::BeginTable("table1", 3, flags, outer_size))
6641
{
6642
for (int row = 0; row < 10; row++)
6643
{
6644
ImGui::TableNextRow();
6645
for (int column = 0; column < 3; column++)
6646
{
6647
ImGui::TableNextColumn();
6648
ImGui::Text("Cell %d,%d", column, row);
6649
}
6650
}
6651
ImGui::EndTable();
6652
}
6653
ImGui::SameLine();
6654
ImGui::Text("Hello!");
6655
6656
ImGui::Spacing();
6657
6658
ImGui::Text("Using explicit size:");
6659
if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6660
{
6661
for (int row = 0; row < 5; row++)
6662
{
6663
ImGui::TableNextRow();
6664
for (int column = 0; column < 3; column++)
6665
{
6666
ImGui::TableNextColumn();
6667
ImGui::Text("Cell %d,%d", column, row);
6668
}
6669
}
6670
ImGui::EndTable();
6671
}
6672
ImGui::SameLine();
6673
if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6674
{
6675
const float rows_height = TEXT_BASE_HEIGHT * 1.5f + ImGui::GetStyle().CellPadding.y * 2.0f;
6676
for (int row = 0; row < 3; row++)
6677
{
6678
ImGui::TableNextRow(0, rows_height);
6679
for (int column = 0; column < 3; column++)
6680
{
6681
ImGui::TableNextColumn();
6682
ImGui::Text("Cell %d,%d", column, row);
6683
}
6684
}
6685
ImGui::EndTable();
6686
}
6687
6688
ImGui::TreePop();
6689
}
6690
6691
if (open_action != -1)
6692
ImGui::SetNextItemOpen(open_action != 0);
6693
IMGUI_DEMO_MARKER("Tables/Background color");
6694
if (ImGui::TreeNode("Background color"))
6695
{
6696
static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
6697
static int row_bg_type = 1;
6698
static int row_bg_target = 1;
6699
static int cell_bg_type = 1;
6700
6701
PushStyleCompact();
6702
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
6703
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6704
ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
6705
ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
6706
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.");
6707
ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
6708
IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
6709
IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
6710
IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
6711
PopStyleCompact();
6712
6713
if (ImGui::BeginTable("table1", 5, flags))
6714
{
6715
for (int row = 0; row < 6; row++)
6716
{
6717
ImGui::TableNextRow();
6718
6719
// Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
6720
// 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.
6721
if (row_bg_type != 0)
6722
{
6723
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?
6724
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
6725
}
6726
6727
// Fill cells
6728
for (int column = 0; column < 5; column++)
6729
{
6730
ImGui::TableSetColumnIndex(column);
6731
ImGui::Text("%c%c", 'A' + row, '0' + column);
6732
6733
// Change background of Cells B1->C2
6734
// Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
6735
// (the CellBg color will be blended over the RowBg and ColumnBg colors)
6736
// We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
6737
if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
6738
{
6739
ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
6740
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
6741
}
6742
}
6743
}
6744
ImGui::EndTable();
6745
}
6746
ImGui::TreePop();
6747
}
6748
6749
if (open_action != -1)
6750
ImGui::SetNextItemOpen(open_action != 0);
6751
IMGUI_DEMO_MARKER("Tables/Tree view");
6752
if (ImGui::TreeNode("Tree view"))
6753
{
6754
static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
6755
6756
static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_DrawLinesFull;
6757
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth);
6758
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanLabelWidth);
6759
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns);
6760
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_LabelSpanAllColumns);
6761
ImGui::SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns");
6762
6763
HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
6764
if (ImGui::BeginTable("3ways", 3, table_flags))
6765
{
6766
// The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
6767
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
6768
ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
6769
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
6770
ImGui::TableHeadersRow();
6771
6772
// Simple storage to output a dummy file-system.
6773
struct MyTreeNode
6774
{
6775
const char* Name;
6776
const char* Type;
6777
int Size;
6778
int ChildIdx;
6779
int ChildCount;
6780
static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
6781
{
6782
ImGui::TableNextRow();
6783
ImGui::TableNextColumn();
6784
const bool is_folder = (node->ChildCount > 0);
6785
6786
ImGuiTreeNodeFlags node_flags = tree_node_flags_base;
6787
if (node != &all_nodes[0])
6788
node_flags &= ~ImGuiTreeNodeFlags_LabelSpanAllColumns; // Only demonstrate this on the root node.
6789
6790
if (is_folder)
6791
{
6792
bool open = ImGui::TreeNodeEx(node->Name, node_flags);
6793
if ((node_flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) == 0)
6794
{
6795
ImGui::TableNextColumn();
6796
ImGui::TextDisabled("--");
6797
ImGui::TableNextColumn();
6798
ImGui::TextUnformatted(node->Type);
6799
}
6800
if (open)
6801
{
6802
for (int child_n = 0; child_n < node->ChildCount; child_n++)
6803
DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
6804
ImGui::TreePop();
6805
}
6806
}
6807
else
6808
{
6809
ImGui::TreeNodeEx(node->Name, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
6810
ImGui::TableNextColumn();
6811
ImGui::Text("%d", node->Size);
6812
ImGui::TableNextColumn();
6813
ImGui::TextUnformatted(node->Type);
6814
}
6815
}
6816
};
6817
static const MyTreeNode nodes[] =
6818
{
6819
{ "Root with Long Name", "Folder", -1, 1, 3 }, // 0
6820
{ "Music", "Folder", -1, 4, 2 }, // 1
6821
{ "Textures", "Folder", -1, 6, 3 }, // 2
6822
{ "desktop.ini", "System file", 1024, -1,-1 }, // 3
6823
{ "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4
6824
{ "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5
6825
{ "Image001.png", "Image file", 203128, -1,-1 }, // 6
6826
{ "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7
6827
{ "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8
6828
};
6829
6830
MyTreeNode::DisplayNode(&nodes[0], nodes);
6831
6832
ImGui::EndTable();
6833
}
6834
ImGui::TreePop();
6835
}
6836
6837
if (open_action != -1)
6838
ImGui::SetNextItemOpen(open_action != 0);
6839
IMGUI_DEMO_MARKER("Tables/Item width");
6840
if (ImGui::TreeNode("Item width"))
6841
{
6842
HelpMarker(
6843
"Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
6844
"Note that on auto-resizing non-resizable fixed columns, querying the content width for "
6845
"e.g. right-alignment doesn't make sense.");
6846
if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
6847
{
6848
ImGui::TableSetupColumn("small");
6849
ImGui::TableSetupColumn("half");
6850
ImGui::TableSetupColumn("right-align");
6851
ImGui::TableHeadersRow();
6852
6853
for (int row = 0; row < 3; row++)
6854
{
6855
ImGui::TableNextRow();
6856
if (row == 0)
6857
{
6858
// Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
6859
ImGui::TableSetColumnIndex(0);
6860
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
6861
ImGui::TableSetColumnIndex(1);
6862
ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
6863
ImGui::TableSetColumnIndex(2);
6864
ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
6865
}
6866
6867
// Draw our contents
6868
static float dummy_f = 0.0f;
6869
ImGui::PushID(row);
6870
ImGui::TableSetColumnIndex(0);
6871
ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
6872
ImGui::TableSetColumnIndex(1);
6873
ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
6874
ImGui::TableSetColumnIndex(2);
6875
ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned
6876
ImGui::PopID();
6877
}
6878
ImGui::EndTable();
6879
}
6880
ImGui::TreePop();
6881
}
6882
6883
// Demonstrate using TableHeader() calls instead of TableHeadersRow()
6884
if (open_action != -1)
6885
ImGui::SetNextItemOpen(open_action != 0);
6886
IMGUI_DEMO_MARKER("Tables/Custom headers");
6887
if (ImGui::TreeNode("Custom headers"))
6888
{
6889
const int COLUMNS_COUNT = 3;
6890
if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6891
{
6892
ImGui::TableSetupColumn("Apricot");
6893
ImGui::TableSetupColumn("Banana");
6894
ImGui::TableSetupColumn("Cherry");
6895
6896
// Dummy entire-column selection storage
6897
// FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
6898
static bool column_selected[3] = {};
6899
6900
// Instead of calling TableHeadersRow() we'll submit custom headers ourselves.
6901
// (A different approach is also possible:
6902
// - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call.
6903
// - Call TableHeadersRow() normally. This will submit TableHeader() with no name.
6904
// - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().)
6905
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
6906
for (int column = 0; column < COLUMNS_COUNT; column++)
6907
{
6908
ImGui::TableSetColumnIndex(column);
6909
const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
6910
ImGui::PushID(column);
6911
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
6912
ImGui::Checkbox("##checkall", &column_selected[column]);
6913
ImGui::PopStyleVar();
6914
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
6915
ImGui::TableHeader(column_name);
6916
ImGui::PopID();
6917
}
6918
6919
// Submit table contents
6920
for (int row = 0; row < 5; row++)
6921
{
6922
ImGui::TableNextRow();
6923
for (int column = 0; column < 3; column++)
6924
{
6925
char buf[32];
6926
sprintf(buf, "Cell %d,%d", column, row);
6927
ImGui::TableSetColumnIndex(column);
6928
ImGui::Selectable(buf, column_selected[column]);
6929
}
6930
}
6931
ImGui::EndTable();
6932
}
6933
ImGui::TreePop();
6934
}
6935
6936
// Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
6937
if (open_action != -1)
6938
ImGui::SetNextItemOpen(open_action != 0);
6939
IMGUI_DEMO_MARKER("Tables/Angled headers");
6940
if (ImGui::TreeNode("Angled headers"))
6941
{
6942
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" };
6943
const int columns_count = IM_COUNTOF(column_names);
6944
const int rows_count = 12;
6945
6946
static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
6947
static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
6948
static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
6949
static int frozen_cols = 1;
6950
static int frozen_rows = 2;
6951
ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
6952
ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
6953
ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
6954
ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable);
6955
ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
6956
ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
6957
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6958
ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2);
6959
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6960
ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
6961
ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
6962
6963
if (ImGui::TreeNode("Style settings"))
6964
{
6965
ImGui::SameLine();
6966
HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.");
6967
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6968
ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f);
6969
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6970
ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
6971
ImGui::TreePop();
6972
}
6973
6974
if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
6975
{
6976
ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
6977
for (int n = 1; n < columns_count; n++)
6978
ImGui::TableSetupColumn(column_names[n], column_flags);
6979
ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows);
6980
6981
ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
6982
ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions.
6983
for (int row = 0; row < rows_count; row++)
6984
{
6985
ImGui::PushID(row);
6986
ImGui::TableNextRow();
6987
ImGui::TableSetColumnIndex(0);
6988
ImGui::AlignTextToFramePadding();
6989
ImGui::Text("Track %d", row);
6990
for (int column = 1; column < columns_count; column++)
6991
if (ImGui::TableSetColumnIndex(column))
6992
{
6993
ImGui::PushID(column);
6994
ImGui::Checkbox("", &bools[row * columns_count + column]);
6995
ImGui::PopID();
6996
}
6997
ImGui::PopID();
6998
}
6999
ImGui::EndTable();
7000
}
7001
ImGui::TreePop();
7002
}
7003
7004
// Demonstrate creating custom context menus inside columns,
7005
// while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
7006
if (open_action != -1)
7007
ImGui::SetNextItemOpen(open_action != 0);
7008
IMGUI_DEMO_MARKER("Tables/Context menus");
7009
if (ImGui::TreeNode("Context menus"))
7010
{
7011
HelpMarker(
7012
"By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
7013
"Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
7014
static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
7015
7016
PushStyleCompact();
7017
ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
7018
PopStyleCompact();
7019
7020
// Context Menus: first example
7021
// [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
7022
// [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
7023
const int COLUMNS_COUNT = 3;
7024
if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
7025
{
7026
ImGui::TableSetupColumn("One");
7027
ImGui::TableSetupColumn("Two");
7028
ImGui::TableSetupColumn("Three");
7029
7030
// [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
7031
ImGui::TableHeadersRow();
7032
7033
// Submit dummy contents
7034
for (int row = 0; row < 4; row++)
7035
{
7036
ImGui::TableNextRow();
7037
for (int column = 0; column < COLUMNS_COUNT; column++)
7038
{
7039
ImGui::TableSetColumnIndex(column);
7040
ImGui::Text("Cell %d,%d", column, row);
7041
}
7042
}
7043
ImGui::EndTable();
7044
}
7045
7046
// Context Menus: second example
7047
// [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
7048
// [2.2] Right-click on the ".." to open a custom popup
7049
// [2.3] Right-click in columns to open another custom popup
7050
HelpMarker(
7051
"Demonstrate mixing table context menu (over header), item context button (over button) "
7052
"and custom per-column context menu (over column body).");
7053
ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
7054
if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
7055
{
7056
ImGui::TableSetupColumn("One");
7057
ImGui::TableSetupColumn("Two");
7058
ImGui::TableSetupColumn("Three");
7059
7060
// [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
7061
ImGui::TableHeadersRow();
7062
for (int row = 0; row < 4; row++)
7063
{
7064
ImGui::TableNextRow();
7065
for (int column = 0; column < COLUMNS_COUNT; column++)
7066
{
7067
// Submit dummy contents
7068
ImGui::TableSetColumnIndex(column);
7069
ImGui::Text("Cell %d,%d", column, row);
7070
ImGui::SameLine();
7071
7072
// [2.2] Right-click on the ".." to open a custom popup
7073
ImGui::PushID(row * COLUMNS_COUNT + column);
7074
ImGui::SmallButton("..");
7075
if (ImGui::BeginPopupContextItem())
7076
{
7077
ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
7078
if (ImGui::Button("Close"))
7079
ImGui::CloseCurrentPopup();
7080
ImGui::EndPopup();
7081
}
7082
ImGui::PopID();
7083
}
7084
}
7085
7086
// [2.3] Right-click anywhere in columns to open another custom popup
7087
// (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
7088
// to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
7089
int hovered_column = -1;
7090
for (int column = 0; column < COLUMNS_COUNT + 1; column++)
7091
{
7092
ImGui::PushID(column);
7093
if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
7094
hovered_column = column;
7095
if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
7096
ImGui::OpenPopup("MyPopup");
7097
if (ImGui::BeginPopup("MyPopup"))
7098
{
7099
if (column == COLUMNS_COUNT)
7100
ImGui::Text("This is a custom popup for unused space after the last column.");
7101
else
7102
ImGui::Text("This is a custom popup for Column %d", column);
7103
if (ImGui::Button("Close"))
7104
ImGui::CloseCurrentPopup();
7105
ImGui::EndPopup();
7106
}
7107
ImGui::PopID();
7108
}
7109
7110
ImGui::EndTable();
7111
ImGui::Text("Hovered column: %d", hovered_column);
7112
}
7113
ImGui::TreePop();
7114
}
7115
7116
// Demonstrate creating multiple tables with the same ID
7117
if (open_action != -1)
7118
ImGui::SetNextItemOpen(open_action != 0);
7119
IMGUI_DEMO_MARKER("Tables/Synced instances");
7120
if (ImGui::TreeNode("Synced instances"))
7121
{
7122
HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
7123
7124
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
7125
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
7126
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
7127
ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
7128
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
7129
for (int n = 0; n < 3; n++)
7130
{
7131
char buf[32];
7132
sprintf(buf, "Synced Table %d", n);
7133
bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
7134
if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
7135
{
7136
ImGui::TableSetupColumn("One");
7137
ImGui::TableSetupColumn("Two");
7138
ImGui::TableSetupColumn("Three");
7139
ImGui::TableHeadersRow();
7140
const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
7141
for (int cell = 0; cell < cell_count; cell++)
7142
{
7143
ImGui::TableNextColumn();
7144
ImGui::Text("this cell %d", cell);
7145
}
7146
ImGui::EndTable();
7147
}
7148
}
7149
ImGui::TreePop();
7150
}
7151
7152
// Demonstrate using Sorting facilities
7153
// This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
7154
// Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
7155
static const char* template_items_names[] =
7156
{
7157
"Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
7158
"Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
7159
};
7160
if (open_action != -1)
7161
ImGui::SetNextItemOpen(open_action != 0);
7162
IMGUI_DEMO_MARKER("Tables/Sorting");
7163
if (ImGui::TreeNode("Sorting"))
7164
{
7165
// Create item list
7166
static ImVector<MyItem> items;
7167
if (items.Size == 0)
7168
{
7169
items.resize(50, MyItem());
7170
for (int n = 0; n < items.Size; n++)
7171
{
7172
const int template_n = n % IM_COUNTOF(template_items_names);
7173
MyItem& item = items[n];
7174
item.ID = n;
7175
item.Name = template_items_names[template_n];
7176
item.Quantity = (n * n - n) % 20; // Assign default quantities
7177
}
7178
}
7179
7180
// Options
7181
static ImGuiTableFlags flags =
7182
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
7183
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
7184
| ImGuiTableFlags_ScrollY;
7185
PushStyleCompact();
7186
ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
7187
ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
7188
ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
7189
ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
7190
PopStyleCompact();
7191
7192
if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
7193
{
7194
// Declare columns
7195
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7196
// This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7197
// Demonstrate using a mixture of flags among available sort-related flags:
7198
// - ImGuiTableColumnFlags_DefaultSort
7199
// - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
7200
// - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
7201
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID);
7202
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
7203
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
7204
ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
7205
ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
7206
ImGui::TableHeadersRow();
7207
7208
// Sort our data if sort specs have been changed!
7209
if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
7210
if (sort_specs->SpecsDirty)
7211
{
7212
MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7213
sort_specs->SpecsDirty = false;
7214
}
7215
7216
// Demonstrate using clipper for large vertical lists
7217
ImGuiListClipper clipper;
7218
clipper.Begin(items.Size);
7219
while (clipper.Step())
7220
for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7221
{
7222
// Display a data item
7223
MyItem* item = &items[row_n];
7224
ImGui::PushID(item->ID);
7225
ImGui::TableNextRow();
7226
ImGui::TableNextColumn();
7227
ImGui::Text("%04d", item->ID);
7228
ImGui::TableNextColumn();
7229
ImGui::TextUnformatted(item->Name);
7230
ImGui::TableNextColumn();
7231
ImGui::SmallButton("None");
7232
ImGui::TableNextColumn();
7233
ImGui::Text("%d", item->Quantity);
7234
ImGui::PopID();
7235
}
7236
ImGui::EndTable();
7237
}
7238
ImGui::TreePop();
7239
}
7240
7241
// In this example we'll expose most table flags and settings.
7242
// For specific flags and settings refer to the corresponding section for more detailed explanation.
7243
// This section is mostly useful to experiment with combining certain flags or settings with each others.
7244
//ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
7245
if (open_action != -1)
7246
ImGui::SetNextItemOpen(open_action != 0);
7247
IMGUI_DEMO_MARKER("Tables/Advanced");
7248
if (ImGui::TreeNode("Advanced"))
7249
{
7250
static ImGuiTableFlags flags =
7251
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
7252
| ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
7253
| ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
7254
| ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
7255
| ImGuiTableFlags_SizingFixedFit;
7256
static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
7257
7258
enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
7259
static int contents_type = CT_SelectableSpanRow;
7260
const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
7261
static int freeze_cols = 1;
7262
static int freeze_rows = 1;
7263
static int items_count = IM_COUNTOF(template_items_names) * 2;
7264
static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
7265
static float row_min_height = 0.0f; // Auto
7266
static float inner_width_with_scroll = 0.0f; // Auto-extend
7267
static bool outer_size_enabled = true;
7268
static bool show_headers = true;
7269
static bool show_wrapped_text = false;
7270
//static ImGuiTextFilter filter;
7271
//ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
7272
if (ImGui::TreeNode("Options"))
7273
{
7274
// Make the UI compact because there are so many fields
7275
PushStyleCompact();
7276
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
7277
7278
if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
7279
{
7280
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
7281
ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
7282
ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
7283
ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
7284
ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
7285
ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
7286
ImGui::TreePop();
7287
}
7288
7289
if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
7290
{
7291
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
7292
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
7293
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
7294
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
7295
ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
7296
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
7297
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
7298
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers)");
7299
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)");
7300
ImGui::TreePop();
7301
}
7302
7303
if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
7304
{
7305
EditTableSizingFlags(&flags);
7306
ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
7307
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
7308
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.");
7309
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
7310
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.");
7311
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
7312
ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
7313
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
7314
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.");
7315
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
7316
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.");
7317
ImGui::TreePop();
7318
}
7319
7320
if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
7321
{
7322
ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
7323
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
7324
ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
7325
ImGui::TreePop();
7326
}
7327
7328
if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
7329
{
7330
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
7331
ImGui::SameLine();
7332
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
7333
ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
7334
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
7335
ImGui::SameLine();
7336
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
7337
ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
7338
ImGui::TreePop();
7339
}
7340
7341
if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
7342
{
7343
ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
7344
ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
7345
ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
7346
ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
7347
ImGui::TreePop();
7348
}
7349
7350
if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
7351
{
7352
ImGui::Checkbox("show_headers", &show_headers);
7353
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
7354
ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
7355
ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
7356
ImGui::TreePop();
7357
}
7358
7359
if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
7360
{
7361
ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
7362
7363
ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
7364
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7365
ImGui::Checkbox("outer_size", &outer_size_enabled);
7366
ImGui::SameLine();
7367
HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
7368
"- The table is output directly in the parent window.\n"
7369
"- OuterSize.x < 0.0f will right-align the table.\n"
7370
"- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
7371
"- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
7372
7373
// From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
7374
// To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
7375
ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
7376
7377
ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
7378
ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
7379
7380
ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
7381
ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_COUNTOF(contents_type_names));
7382
//filter.Draw("filter");
7383
ImGui::TreePop();
7384
}
7385
7386
ImGui::PopItemWidth();
7387
PopStyleCompact();
7388
ImGui::Spacing();
7389
ImGui::TreePop();
7390
}
7391
7392
// Update item list if we changed the number of items
7393
static ImVector<MyItem> items;
7394
static ImVector<int> selection;
7395
static bool items_need_sort = false;
7396
if (items.Size != items_count)
7397
{
7398
items.resize(items_count, MyItem());
7399
for (int n = 0; n < items_count; n++)
7400
{
7401
const int template_n = n % IM_COUNTOF(template_items_names);
7402
MyItem& item = items[n];
7403
item.ID = n;
7404
item.Name = template_items_names[template_n];
7405
item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
7406
}
7407
}
7408
7409
const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
7410
const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
7411
ImVec2 table_scroll_cur, table_scroll_max; // For debug display
7412
const ImDrawList* table_draw_list = NULL; // "
7413
7414
// Submit table
7415
const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
7416
if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
7417
{
7418
// Declare columns
7419
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7420
// This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7421
ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
7422
ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
7423
ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
7424
ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
7425
ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
7426
ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
7427
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
7428
7429
// Sort our data if sort specs have been changed!
7430
ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
7431
if (sort_specs && sort_specs->SpecsDirty)
7432
items_need_sort = true;
7433
if (sort_specs && items_need_sort && items.Size > 1)
7434
{
7435
MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7436
sort_specs->SpecsDirty = false;
7437
}
7438
items_need_sort = false;
7439
7440
// Take note of whether we are currently sorting based on the Quantity field,
7441
// we will use this to trigger sorting when we know the data of this column has been modified.
7442
const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
7443
7444
// Show headers
7445
if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
7446
ImGui::TableAngledHeadersRow();
7447
if (show_headers)
7448
ImGui::TableHeadersRow();
7449
7450
// Show data
7451
// FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
7452
#if 1
7453
// Demonstrate using clipper for large vertical lists
7454
ImGuiListClipper clipper;
7455
clipper.Begin(items.Size);
7456
while (clipper.Step())
7457
{
7458
for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7459
#else
7460
// Without clipper
7461
{
7462
for (int row_n = 0; row_n < items.Size; row_n++)
7463
#endif
7464
{
7465
MyItem* item = &items[row_n];
7466
//if (!filter.PassFilter(item->Name))
7467
// continue;
7468
7469
const bool item_is_selected = selection.contains(item->ID);
7470
ImGui::PushID(item->ID);
7471
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
7472
7473
// For the demo purpose we can select among different type of items submitted in the first column
7474
ImGui::TableSetColumnIndex(0);
7475
char label[32];
7476
sprintf(label, "%04d", item->ID);
7477
if (contents_type == CT_Text)
7478
ImGui::TextUnformatted(label);
7479
else if (contents_type == CT_Button)
7480
ImGui::Button(label);
7481
else if (contents_type == CT_SmallButton)
7482
ImGui::SmallButton(label);
7483
else if (contents_type == CT_FillButton)
7484
ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
7485
else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
7486
{
7487
ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
7488
if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
7489
{
7490
if (ImGui::GetIO().KeyCtrl)
7491
{
7492
if (item_is_selected)
7493
selection.find_erase_unsorted(item->ID);
7494
else
7495
selection.push_back(item->ID);
7496
}
7497
else
7498
{
7499
selection.clear();
7500
selection.push_back(item->ID);
7501
}
7502
}
7503
}
7504
7505
if (ImGui::TableSetColumnIndex(1))
7506
ImGui::TextUnformatted(item->Name);
7507
7508
// Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
7509
// and we are currently sorting on the column showing the Quantity.
7510
// To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
7511
// You will probably need some extra logic if you want to automatically sort when a specific entry changes.
7512
if (ImGui::TableSetColumnIndex(2))
7513
{
7514
if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
7515
if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7516
ImGui::SameLine();
7517
if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
7518
if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7519
}
7520
7521
if (ImGui::TableSetColumnIndex(3))
7522
ImGui::Text("%d", item->Quantity);
7523
7524
ImGui::TableSetColumnIndex(4);
7525
if (show_wrapped_text)
7526
ImGui::TextWrapped("Lorem ipsum dolor sit amet");
7527
else
7528
ImGui::Text("Lorem ipsum dolor sit amet");
7529
7530
if (ImGui::TableSetColumnIndex(5))
7531
ImGui::Text("1234");
7532
7533
ImGui::PopID();
7534
}
7535
}
7536
7537
// Store some info to display debug details below
7538
table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
7539
table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
7540
table_draw_list = ImGui::GetWindowDrawList();
7541
ImGui::EndTable();
7542
}
7543
static bool show_debug_details = false;
7544
ImGui::Checkbox("Debug details", &show_debug_details);
7545
if (show_debug_details && table_draw_list)
7546
{
7547
ImGui::SameLine(0.0f, 0.0f);
7548
const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
7549
if (table_draw_list == parent_draw_list)
7550
ImGui::Text(": DrawCmd: +%d (in same window)",
7551
table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
7552
else
7553
ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
7554
table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
7555
}
7556
ImGui::TreePop();
7557
}
7558
7559
ImGui::PopID();
7560
7561
DemoWindowColumns();
7562
7563
if (disable_indent)
7564
ImGui::PopStyleVar();
7565
}
7566
7567
// Demonstrate old/legacy Columns API!
7568
// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
7569
static void DemoWindowColumns()
7570
{
7571
IMGUI_DEMO_MARKER("Columns (legacy API)");
7572
bool open = ImGui::TreeNode("Legacy Columns API");
7573
ImGui::SameLine();
7574
HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
7575
if (!open)
7576
return;
7577
7578
// Basic columns
7579
IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
7580
if (ImGui::TreeNode("Basic"))
7581
{
7582
ImGui::Text("Without border:");
7583
ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
7584
ImGui::Separator();
7585
for (int n = 0; n < 14; n++)
7586
{
7587
char label[32];
7588
sprintf(label, "Item %d", n);
7589
if (ImGui::Selectable(label)) {}
7590
//if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
7591
ImGui::NextColumn();
7592
}
7593
ImGui::Columns(1);
7594
ImGui::Separator();
7595
7596
ImGui::Text("With border:");
7597
ImGui::Columns(4, "mycolumns"); // 4-ways, with border
7598
ImGui::Separator();
7599
ImGui::Text("ID"); ImGui::NextColumn();
7600
ImGui::Text("Name"); ImGui::NextColumn();
7601
ImGui::Text("Path"); ImGui::NextColumn();
7602
ImGui::Text("Hovered"); ImGui::NextColumn();
7603
ImGui::Separator();
7604
const char* names[3] = { "One", "Two", "Three" };
7605
const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
7606
static int selected = -1;
7607
for (int i = 0; i < 3; i++)
7608
{
7609
char label[32];
7610
sprintf(label, "%04d", i);
7611
if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
7612
selected = i;
7613
bool hovered = ImGui::IsItemHovered();
7614
ImGui::NextColumn();
7615
ImGui::Text(names[i]); ImGui::NextColumn();
7616
ImGui::Text(paths[i]); ImGui::NextColumn();
7617
ImGui::Text("%d", hovered); ImGui::NextColumn();
7618
}
7619
ImGui::Columns(1);
7620
ImGui::Separator();
7621
ImGui::TreePop();
7622
}
7623
7624
IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
7625
if (ImGui::TreeNode("Borders"))
7626
{
7627
// NB: Future columns API should allow automatic horizontal borders.
7628
static bool h_borders = true;
7629
static bool v_borders = true;
7630
static int columns_count = 4;
7631
const int lines_count = 3;
7632
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7633
ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
7634
if (columns_count < 2)
7635
columns_count = 2;
7636
ImGui::SameLine();
7637
ImGui::Checkbox("horizontal", &h_borders);
7638
ImGui::SameLine();
7639
ImGui::Checkbox("vertical", &v_borders);
7640
ImGui::Columns(columns_count, NULL, v_borders);
7641
for (int i = 0; i < columns_count * lines_count; i++)
7642
{
7643
if (h_borders && ImGui::GetColumnIndex() == 0)
7644
ImGui::Separator();
7645
ImGui::PushID(i);
7646
ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
7647
ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
7648
ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
7649
ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
7650
ImGui::Text("Long text that is likely to clip");
7651
ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
7652
ImGui::PopID();
7653
ImGui::NextColumn();
7654
}
7655
ImGui::Columns(1);
7656
if (h_borders)
7657
ImGui::Separator();
7658
ImGui::TreePop();
7659
}
7660
7661
// Create multiple items in a same cell before switching to next column
7662
IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
7663
if (ImGui::TreeNode("Mixed items"))
7664
{
7665
ImGui::Columns(3, "mixed");
7666
ImGui::Separator();
7667
7668
ImGui::Text("Hello");
7669
ImGui::Button("Banana");
7670
ImGui::NextColumn();
7671
7672
ImGui::Text("ImGui");
7673
ImGui::Button("Apple");
7674
static float foo = 1.0f;
7675
ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
7676
ImGui::Text("An extra line here.");
7677
ImGui::NextColumn();
7678
7679
ImGui::Text("Sailor");
7680
ImGui::Button("Corniflower");
7681
static float bar = 1.0f;
7682
ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
7683
ImGui::NextColumn();
7684
7685
if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7686
if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7687
if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7688
ImGui::Columns(1);
7689
ImGui::Separator();
7690
ImGui::TreePop();
7691
}
7692
7693
// Word wrapping
7694
IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
7695
if (ImGui::TreeNode("Word-wrapping"))
7696
{
7697
ImGui::Columns(2, "word-wrapping");
7698
ImGui::Separator();
7699
ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7700
ImGui::TextWrapped("Hello Left");
7701
ImGui::NextColumn();
7702
ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7703
ImGui::TextWrapped("Hello Right");
7704
ImGui::Columns(1);
7705
ImGui::Separator();
7706
ImGui::TreePop();
7707
}
7708
7709
IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
7710
if (ImGui::TreeNode("Horizontal Scrolling"))
7711
{
7712
ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
7713
ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
7714
ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
7715
ImGui::Columns(10);
7716
7717
// Also demonstrate using clipper for large vertical lists
7718
int ITEMS_COUNT = 2000;
7719
ImGuiListClipper clipper;
7720
clipper.Begin(ITEMS_COUNT);
7721
while (clipper.Step())
7722
{
7723
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7724
for (int j = 0; j < 10; j++)
7725
{
7726
ImGui::Text("Line %d Column %d...", i, j);
7727
ImGui::NextColumn();
7728
}
7729
}
7730
ImGui::Columns(1);
7731
ImGui::EndChild();
7732
ImGui::TreePop();
7733
}
7734
7735
IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
7736
if (ImGui::TreeNode("Tree"))
7737
{
7738
ImGui::Columns(2, "tree", true);
7739
for (int x = 0; x < 3; x++)
7740
{
7741
bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
7742
ImGui::NextColumn();
7743
ImGui::Text("Node contents");
7744
ImGui::NextColumn();
7745
if (open1)
7746
{
7747
for (int y = 0; y < 3; y++)
7748
{
7749
bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
7750
ImGui::NextColumn();
7751
ImGui::Text("Node contents");
7752
if (open2)
7753
{
7754
ImGui::Text("Even more contents");
7755
if (ImGui::TreeNode("Tree in column"))
7756
{
7757
ImGui::Text("The quick brown fox jumps over the lazy dog");
7758
ImGui::TreePop();
7759
}
7760
}
7761
ImGui::NextColumn();
7762
if (open2)
7763
ImGui::TreePop();
7764
}
7765
ImGui::TreePop();
7766
}
7767
}
7768
ImGui::Columns(1);
7769
ImGui::TreePop();
7770
}
7771
7772
ImGui::TreePop();
7773
}
7774
7775
//-----------------------------------------------------------------------------
7776
// [SECTION] DemoWindowInputs()
7777
//-----------------------------------------------------------------------------
7778
7779
static void DemoWindowInputs()
7780
{
7781
IMGUI_DEMO_MARKER("Inputs & Focus");
7782
if (ImGui::CollapsingHeader("Inputs & Focus"))
7783
{
7784
ImGuiIO& io = ImGui::GetIO();
7785
7786
// Display inputs submitted to ImGuiIO
7787
IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
7788
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7789
bool inputs_opened = ImGui::TreeNode("Inputs");
7790
ImGui::SameLine();
7791
HelpMarker(
7792
"This is a simplified view. See more detailed input state:\n"
7793
"- in 'Tools->Metrics/Debugger->Inputs'.\n"
7794
"- in 'Tools->Debug Log->IO'.");
7795
if (inputs_opened)
7796
{
7797
if (ImGui::IsMousePosValid())
7798
ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
7799
else
7800
ImGui::Text("Mouse pos: <INVALID>");
7801
ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
7802
ImGui::Text("Mouse down:");
7803
for (int i = 0; i < IM_COUNTOF(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
7804
ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
7805
ImGui::Text("Mouse clicked count:");
7806
for (int i = 0; i < IM_COUNTOF(io.MouseDown); i++) if (io.MouseClickedCount[i] > 0) { ImGui::SameLine(); ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); }
7807
7808
// We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
7809
// displaying the data for old/new backends.
7810
// User code should never have to go through such hoops!
7811
// You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
7812
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
7813
ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
7814
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); }
7815
ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
7816
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.
7817
7818
ImGui::TreePop();
7819
}
7820
7821
// Display ImGuiIO output flags
7822
IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
7823
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7824
bool outputs_opened = ImGui::TreeNode("Outputs");
7825
ImGui::SameLine();
7826
HelpMarker(
7827
"The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
7828
"to instruct your application of how to route inputs. Typically, when a value is true, it means "
7829
"Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
7830
"The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
7831
"and underlying application should ignore mouse inputs (in practice there are many and more subtle "
7832
"rules leading to how those flags are set).");
7833
if (outputs_opened)
7834
{
7835
ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
7836
ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
7837
ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
7838
ImGui::Text("io.WantTextInput: %d", io.WantTextInput);
7839
ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos);
7840
ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
7841
7842
IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
7843
if (ImGui::TreeNode("WantCapture override"))
7844
{
7845
HelpMarker(
7846
"Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
7847
"Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
7848
"and true when clicking.");
7849
static int capture_override_mouse = -1;
7850
static int capture_override_keyboard = -1;
7851
const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
7852
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7853
ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp);
7854
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7855
ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp);
7856
7857
ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item
7858
if (ImGui::IsItemHovered() && capture_override_mouse != -1)
7859
ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
7860
if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
7861
ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
7862
7863
ImGui::TreePop();
7864
}
7865
ImGui::TreePop();
7866
}
7867
7868
// Demonstrate using Shortcut() and Routing Policies.
7869
// The general flow is:
7870
// - Code interested in a chord (e.g. "Ctrl+A") declares their intent.
7871
// - Multiple locations may be interested in same chord! Routing helps find a winner.
7872
// - Every frame, we resolve all claims and assign one owner if the modifiers are matching.
7873
// - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route.
7874
// - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags.
7875
// - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused.
7876
// TL;DR: Most uses will simply be:
7877
// - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy.
7878
IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts");
7879
if (ImGui::TreeNode("Shortcuts"))
7880
{
7881
static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat;
7882
static ImGuiInputFlags route_type = ImGuiInputFlags_RouteFocused;
7883
ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat);
7884
ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive);
7885
ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused);
7886
ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal);
7887
ImGui::Indent();
7888
ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal);
7889
ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused);
7890
ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive);
7891
ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused);
7892
ImGui::EndDisabled();
7893
ImGui::Unindent();
7894
ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
7895
ImGuiInputFlags flags = route_type | route_options; // Merged flags
7896
if (route_type != ImGuiInputFlags_RouteGlobal)
7897
flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
7898
7899
ImGui::SeparatorText("Using SetNextItemShortcut()");
7900
ImGui::Text("Ctrl+S");
7901
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip);
7902
ImGui::Button("Save");
7903
ImGui::Text("Alt+F");
7904
ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip);
7905
static float f = 0.5f;
7906
ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f);
7907
7908
ImGui::SeparatorText("Using Shortcut()");
7909
const float line_height = ImGui::GetTextLineHeightWithSpacing();
7910
const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A;
7911
7912
ImGui::Text("Ctrl+A");
7913
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7914
7915
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f));
7916
7917
ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true);
7918
ImGui::Text("Press Ctrl+A and see who receives it!");
7919
ImGui::Separator();
7920
7921
// 1: Window polling for Ctrl+A
7922
ImGui::Text("(in WindowA)");
7923
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7924
7925
// 2: InputText also polling for Ctrl+A: it always uses _RouteFocused internally (gets priority when active)
7926
// (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7927
//char str[16] = "Press Ctrl+A";
7928
//ImGui::Spacing();
7929
//ImGui::InputText("InputTextB", str, IM_COUNTOF(str), ImGuiInputTextFlags_ReadOnly);
7930
//ImGuiID item_id = ImGui::GetItemID();
7931
//ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused");
7932
//ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, item_id) ? "PRESSED" : "...");
7933
7934
// 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA
7935
ImGui::BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true);
7936
ImGui::Text("(in ChildD: not using same Shortcut)");
7937
ImGui::Text("IsWindowFocused: %d", ImGui::IsWindowFocused());
7938
ImGui::EndChild();
7939
7940
// 4: Child window polling for Ctrl+A. It is deeper than WindowA and gets priority when focused.
7941
ImGui::BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true);
7942
ImGui::Text("(in ChildE: using same Shortcut)");
7943
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7944
ImGui::EndChild();
7945
7946
// 5: In a popup
7947
if (ImGui::Button("Open Popup"))
7948
ImGui::OpenPopup("PopupF");
7949
if (ImGui::BeginPopup("PopupF"))
7950
{
7951
ImGui::Text("(in PopupF)");
7952
ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7953
// (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7954
//ImGui::InputText("InputTextG", str, IM_COUNTOF(str), ImGuiInputTextFlags_ReadOnly);
7955
//ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "...");
7956
ImGui::EndPopup();
7957
}
7958
ImGui::EndChild();
7959
ImGui::PopStyleColor();
7960
7961
ImGui::TreePop();
7962
}
7963
7964
// Display mouse cursors
7965
IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
7966
if (ImGui::TreeNode("Mouse Cursors"))
7967
{
7968
const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" };
7969
IM_ASSERT(IM_COUNTOF(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
7970
7971
ImGuiMouseCursor current = ImGui::GetMouseCursor();
7972
const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
7973
ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
7974
ImGui::BeginDisabled(true);
7975
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
7976
ImGui::EndDisabled();
7977
7978
ImGui::Text("Hover to see mouse cursors:");
7979
ImGui::SameLine(); HelpMarker(
7980
"Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
7981
"If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
7982
"otherwise your backend needs to handle it.");
7983
for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
7984
{
7985
char label[32];
7986
sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
7987
ImGui::Bullet(); ImGui::Selectable(label, false);
7988
if (ImGui::IsItemHovered())
7989
ImGui::SetMouseCursor(i);
7990
}
7991
ImGui::TreePop();
7992
}
7993
7994
IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
7995
if (ImGui::TreeNode("Tabbing"))
7996
{
7997
ImGui::Text("Use Tab/Shift+Tab to cycle through keyboard editable fields.");
7998
static char buf[32] = "hello";
7999
ImGui::InputText("1", buf, IM_COUNTOF(buf));
8000
ImGui::InputText("2", buf, IM_COUNTOF(buf));
8001
ImGui::InputText("3", buf, IM_COUNTOF(buf));
8002
ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
8003
ImGui::InputText("4 (tab skip)", buf, IM_COUNTOF(buf));
8004
ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
8005
ImGui::PopItemFlag();
8006
ImGui::InputText("5", buf, IM_COUNTOF(buf));
8007
ImGui::TreePop();
8008
}
8009
8010
IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
8011
if (ImGui::TreeNode("Focus from code"))
8012
{
8013
bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
8014
bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
8015
bool focus_3 = ImGui::Button("Focus on 3");
8016
int has_focus = 0;
8017
static char buf[128] = "click on a button to set focus";
8018
8019
if (focus_1) ImGui::SetKeyboardFocusHere();
8020
ImGui::InputText("1", buf, IM_COUNTOF(buf));
8021
if (ImGui::IsItemActive()) has_focus = 1;
8022
8023
if (focus_2) ImGui::SetKeyboardFocusHere();
8024
ImGui::InputText("2", buf, IM_COUNTOF(buf));
8025
if (ImGui::IsItemActive()) has_focus = 2;
8026
8027
ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
8028
if (focus_3) ImGui::SetKeyboardFocusHere();
8029
ImGui::InputText("3 (tab skip)", buf, IM_COUNTOF(buf));
8030
if (ImGui::IsItemActive()) has_focus = 3;
8031
ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
8032
ImGui::PopItemFlag();
8033
8034
if (has_focus)
8035
ImGui::Text("Item with focus: %d", has_focus);
8036
else
8037
ImGui::Text("Item with focus: <none>");
8038
8039
// Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
8040
static float f3[3] = { 0.0f, 0.0f, 0.0f };
8041
int focus_ahead = -1;
8042
if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
8043
if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
8044
if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
8045
if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
8046
ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
8047
8048
ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
8049
ImGui::TreePop();
8050
}
8051
8052
IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
8053
if (ImGui::TreeNode("Dragging"))
8054
{
8055
ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
8056
for (int button = 0; button < 3; button++)
8057
{
8058
ImGui::Text("IsMouseDragging(%d):", button);
8059
ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button));
8060
ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
8061
ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
8062
}
8063
8064
ImGui::Button("Drag Me");
8065
if (ImGui::IsItemActive())
8066
ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
8067
8068
// Drag operations gets "unlocked" when the mouse has moved past a certain threshold
8069
// (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
8070
// threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
8071
ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
8072
ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
8073
ImVec2 mouse_delta = io.MouseDelta;
8074
ImGui::Text("GetMouseDragDelta(0):");
8075
ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
8076
ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
8077
ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
8078
ImGui::TreePop();
8079
}
8080
}
8081
}
8082
8083
//-----------------------------------------------------------------------------
8084
// [SECTION] About Window / ShowAboutWindow()
8085
// Access from Dear ImGui Demo -> Tools -> About
8086
//-----------------------------------------------------------------------------
8087
8088
void ImGui::ShowAboutWindow(bool* p_open)
8089
{
8090
if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
8091
{
8092
ImGui::End();
8093
return;
8094
}
8095
IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
8096
ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
8097
8098
ImGui::TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui");
8099
ImGui::SameLine();
8100
ImGui::TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md");
8101
ImGui::SameLine();
8102
ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki");
8103
ImGui::SameLine();
8104
ImGui::TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions");
8105
ImGui::SameLine();
8106
ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases");
8107
ImGui::SameLine();
8108
ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding");
8109
8110
ImGui::Separator();
8111
ImGui::Text("(c) 2014-2026 Omar Cornut");
8112
ImGui::Text("Developed by Omar Cornut and all Dear ImGui contributors.");
8113
ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
8114
ImGui::Text("If your company uses this, please consider funding the project.");
8115
8116
static bool show_config_info = false;
8117
ImGui::Checkbox("Config/Build Information", &show_config_info);
8118
if (show_config_info)
8119
{
8120
ImGuiIO& io = ImGui::GetIO();
8121
ImGuiStyle& style = ImGui::GetStyle();
8122
8123
bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
8124
ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
8125
ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
8126
if (copy_to_clipboard)
8127
{
8128
ImGui::LogToClipboard();
8129
ImGui::LogText("```cpp\n"); // Back quotes will make text appears without formatting when pasting on GitHub
8130
}
8131
8132
ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
8133
ImGui::Separator();
8134
ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
8135
ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
8136
#ifdef IMGUI_ENABLE_TEST_ENGINE
8137
ImGui::Text("define: IMGUI_ENABLE_TEST_ENGINE");
8138
#endif
8139
#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
8140
ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
8141
#endif
8142
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
8143
ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
8144
#endif
8145
#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
8146
ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
8147
#endif
8148
#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
8149
ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
8150
#endif
8151
#ifdef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
8152
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS");
8153
#endif
8154
#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
8155
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
8156
#endif
8157
#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
8158
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
8159
#endif
8160
#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
8161
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
8162
#endif
8163
#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
8164
ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
8165
#endif
8166
#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
8167
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
8168
#endif
8169
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
8170
ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
8171
#endif
8172
#ifdef _WIN32
8173
ImGui::Text("define: _WIN32");
8174
#endif
8175
#ifdef _WIN64
8176
ImGui::Text("define: _WIN64");
8177
#endif
8178
#ifdef __linux__
8179
ImGui::Text("define: __linux__");
8180
#endif
8181
#ifdef __APPLE__
8182
ImGui::Text("define: __APPLE__");
8183
#endif
8184
#ifdef _MSC_VER
8185
ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
8186
#endif
8187
#ifdef _MSVC_LANG
8188
ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
8189
#endif
8190
#ifdef __MINGW32__
8191
ImGui::Text("define: __MINGW32__");
8192
#endif
8193
#ifdef __MINGW64__
8194
ImGui::Text("define: __MINGW64__");
8195
#endif
8196
#ifdef __GNUC__
8197
ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
8198
#endif
8199
#ifdef __clang_version__
8200
ImGui::Text("define: __clang_version__=%s", __clang_version__);
8201
#endif
8202
#ifdef __EMSCRIPTEN__
8203
ImGui::Text("define: __EMSCRIPTEN__");
8204
ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
8205
#endif
8206
#ifdef NDEBUG
8207
ImGui::Text("define: NDEBUG");
8208
#endif
8209
8210
// Heuristic to detect no-op IM_ASSERT() macros
8211
// - This is designed so people opening bug reports would convey and notice that they have disabled asserts for Dear ImGui code.
8212
// - 16 is > strlen("((void)(_EXPR))") which we suggested in our imconfig.h template as a possible way to disable.
8213
int assert_runs_expression = 0;
8214
IM_ASSERT(++assert_runs_expression);
8215
int assert_expand_len = (int)strlen(IM_STRINGIFY((IM_ASSERT(true))));
8216
bool assert_maybe_disabled = (!assert_runs_expression || assert_expand_len <= 16);
8217
ImGui::Text("IM_ASSERT: runs expression: %s. expand size: %s%s",
8218
assert_runs_expression ? "OK" : "KO", (assert_expand_len > 16) ? "OK" : "KO", assert_maybe_disabled ? " (MAYBE DISABLED?!)" : "");
8219
if (assert_maybe_disabled)
8220
{
8221
ImGui::SameLine();
8222
HelpMarker("IM_ASSERT() calls assert() by default. Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes!");
8223
}
8224
8225
ImGui::Separator();
8226
ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
8227
ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
8228
ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
8229
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
8230
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
8231
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
8232
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
8233
if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard");
8234
if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
8235
if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
8236
if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos");
8237
if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard");
8238
if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
8239
if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
8240
if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
8241
if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
8242
ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
8243
if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
8244
if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
8245
if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
8246
if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
8247
if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) ImGui::Text(" RendererHasTextures");
8248
ImGui::Separator();
8249
ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexData->Width, io.Fonts->TexData->Height);
8250
ImGui::Text("io.Fonts->FontLoaderName: %s", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL");
8251
ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
8252
ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
8253
ImGui::Separator();
8254
ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
8255
ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
8256
ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
8257
ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
8258
ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
8259
ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
8260
ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
8261
8262
if (copy_to_clipboard)
8263
{
8264
ImGui::LogText("\n```\n");
8265
ImGui::LogFinish();
8266
}
8267
ImGui::EndChild();
8268
}
8269
ImGui::End();
8270
}
8271
8272
//-----------------------------------------------------------------------------
8273
// [SECTION] Style Editor / ShowStyleEditor()
8274
//-----------------------------------------------------------------------------
8275
// - ShowStyleSelector()
8276
// - ShowStyleEditor()
8277
//-----------------------------------------------------------------------------
8278
8279
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
8280
bool ImGui::ShowStyleSelector(const char* label)
8281
{
8282
// FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active.
8283
// So we keep track of last active one among our limited selection.
8284
static int style_idx = -1;
8285
const char* style_names[] = { "Dark", "Light", "Classic" };
8286
bool ret = false;
8287
if (ImGui::BeginCombo(label, (style_idx >= 0 && style_idx < IM_COUNTOF(style_names)) ? style_names[style_idx] : ""))
8288
{
8289
for (int n = 0; n < IM_COUNTOF(style_names); n++)
8290
{
8291
if (ImGui::Selectable(style_names[n], style_idx == n, ImGuiSelectableFlags_SelectOnNav))
8292
{
8293
style_idx = n;
8294
ret = true;
8295
switch (style_idx)
8296
{
8297
case 0: ImGui::StyleColorsDark(); break;
8298
case 1: ImGui::StyleColorsLight(); break;
8299
case 2: ImGui::StyleColorsClassic(); break;
8300
}
8301
}
8302
else if (style_idx == n)
8303
ImGui::SetItemDefaultFocus();
8304
}
8305
ImGui::EndCombo();
8306
}
8307
return ret;
8308
}
8309
8310
static const char* GetTreeLinesFlagsName(ImGuiTreeNodeFlags flags)
8311
{
8312
if (flags == ImGuiTreeNodeFlags_DrawLinesNone) return "DrawLinesNone";
8313
if (flags == ImGuiTreeNodeFlags_DrawLinesFull) return "DrawLinesFull";
8314
if (flags == ImGuiTreeNodeFlags_DrawLinesToNodes) return "DrawLinesToNodes";
8315
return "";
8316
}
8317
8318
// We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code.
8319
void ImGui::ShowStyleEditor(ImGuiStyle* ref)
8320
{
8321
IMGUI_DEMO_MARKER("Tools/Style Editor");
8322
// You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
8323
// (without a reference style pointer, we will use one compared locally as a reference)
8324
ImGuiStyle& style = GetStyle();
8325
static ImGuiStyle ref_saved_style;
8326
8327
// Default to using internal storage as reference
8328
static bool init = true;
8329
if (init && ref == NULL)
8330
ref_saved_style = style;
8331
init = false;
8332
if (ref == NULL)
8333
ref = &ref_saved_style;
8334
8335
PushItemWidth(GetWindowWidth() * 0.50f);
8336
8337
{
8338
// General
8339
SeparatorText("General");
8340
if ((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0)
8341
{
8342
BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!");
8343
BulletText("For instructions, see:");
8344
SameLine();
8345
TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md");
8346
}
8347
8348
if (ShowStyleSelector("Colors##Selector"))
8349
ref_saved_style = style;
8350
ShowFontSelector("Fonts##Selector");
8351
if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f"))
8352
style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work.
8353
SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize());
8354
DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f);
8355
//BeginDisabled(GetIO().ConfigDpiScaleFonts);
8356
DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 4.0f);
8357
//SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten.");
8358
//EndDisabled();
8359
8360
// Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
8361
if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
8362
style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
8363
{ bool border = (style.WindowBorderSize > 0.0f); if (Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
8364
SameLine();
8365
{ bool border = (style.FrameBorderSize > 0.0f); if (Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } }
8366
SameLine();
8367
{ bool border = (style.PopupBorderSize > 0.0f); if (Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } }
8368
}
8369
8370
// Save/Revert button
8371
if (Button("Save Ref"))
8372
*ref = ref_saved_style = style;
8373
SameLine();
8374
if (Button("Revert Ref"))
8375
style = *ref;
8376
SameLine();
8377
HelpMarker(
8378
"Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
8379
"Use \"Export\" below to save them somewhere.");
8380
8381
SeparatorText("Details");
8382
if (BeginTabBar("##tabs", ImGuiTabBarFlags_None))
8383
{
8384
if (BeginTabItem("Sizes"))
8385
{
8386
SeparatorText("Main");
8387
SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
8388
SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
8389
SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
8390
SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
8391
SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
8392
SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
8393
SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
8394
8395
SeparatorText("Borders");
8396
SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
8397
SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
8398
SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
8399
SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
8400
8401
SeparatorText("Rounding");
8402
SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
8403
SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
8404
SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
8405
SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
8406
SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
8407
8408
SeparatorText("Scrollbar");
8409
SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
8410
SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
8411
SliderFloat("ScrollbarPadding", &style.ScrollbarPadding, 0.0f, 10.0f, "%.0f");
8412
8413
SeparatorText("Tabs");
8414
SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
8415
SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
8416
SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f");
8417
SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
8418
DragFloat("TabMinWidthBase", &style.TabMinWidthBase, 0.5f, 1.0f, 500.0f, "%.0f");
8419
DragFloat("TabMinWidthShrink", &style.TabMinWidthShrink, 0.5f, 1.0f, 500.0f, "%0.f");
8420
DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.5f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f");
8421
DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.5f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f");
8422
SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
8423
8424
SeparatorText("Tables");
8425
SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
8426
SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
8427
SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
8428
8429
SeparatorText("Trees");
8430
bool combo_open = BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags));
8431
SameLine();
8432
HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode.");
8433
if (combo_open)
8434
{
8435
const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes };
8436
for (ImGuiTreeNodeFlags option : options)
8437
if (Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option))
8438
style.TreeLinesFlags = option;
8439
EndCombo();
8440
}
8441
SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 2.0f, "%.0f");
8442
SliderFloat("TreeLinesRounding", &style.TreeLinesRounding, 0.0f, 12.0f, "%.0f");
8443
8444
SeparatorText("Windows");
8445
SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
8446
SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f");
8447
int window_menu_button_position = style.WindowMenuButtonPosition + 1;
8448
if (Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
8449
style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
8450
8451
SeparatorText("Widgets");
8452
SliderFloat("ColorMarkerSize", &style.ColorMarkerSize, 0.0f, 8.0f, "%.0f");
8453
Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
8454
SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
8455
SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
8456
SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
8457
SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
8458
SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
8459
SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
8460
SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f");
8461
SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
8462
SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, 1.0f, "%.0f");
8463
8464
SeparatorText("Tooltips");
8465
for (int n = 0; n < 2; n++)
8466
if (TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
8467
{
8468
ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
8469
CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone);
8470
CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort);
8471
CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal);
8472
CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary);
8473
CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay);
8474
TreePop();
8475
}
8476
8477
SeparatorText("Misc");
8478
SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.");
8479
SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
8480
8481
EndTabItem();
8482
}
8483
8484
if (BeginTabItem("Colors"))
8485
{
8486
static int output_dest = 0;
8487
static bool output_only_modified = true;
8488
if (Button("Export"))
8489
{
8490
if (output_dest == 0)
8491
LogToClipboard();
8492
else
8493
LogToTTY();
8494
LogText("ImVec4* colors = GetStyle().Colors;" IM_NEWLINE);
8495
for (int i = 0; i < ImGuiCol_COUNT; i++)
8496
{
8497
const ImVec4& col = style.Colors[i];
8498
const char* name = GetStyleColorName(i);
8499
if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
8500
LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
8501
name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
8502
}
8503
LogFinish();
8504
}
8505
SameLine(); SetNextItemWidth(GetFontSize() * 10); Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
8506
SameLine(); Checkbox("Only Modified Colors", &output_only_modified);
8507
8508
static ImGuiTextFilter filter;
8509
filter.Draw("Filter colors", GetFontSize() * 16);
8510
8511
static ImGuiColorEditFlags alpha_flags = 0;
8512
if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine();
8513
if (RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } SameLine();
8514
if (RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } SameLine();
8515
HelpMarker(
8516
"In the color list:\n"
8517
"Left-click on color square to open color picker,\n"
8518
"Right-click to open edit options menu.");
8519
8520
SetNextWindowSizeConstraints(ImVec2(0.0f, GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
8521
BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
8522
PushItemWidth(GetFontSize() * -12);
8523
for (int i = 0; i < ImGuiCol_COUNT; i++)
8524
{
8525
const char* name = GetStyleColorName(i);
8526
if (!filter.PassFilter(name))
8527
continue;
8528
PushID(i);
8529
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8530
if (Button("?"))
8531
DebugFlashStyleColor((ImGuiCol)i);
8532
SetItemTooltip("Flash given color to identify places where it is used.");
8533
SameLine();
8534
#endif
8535
ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
8536
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
8537
{
8538
// Tips: in a real user application, you may want to merge and use an icon font into the main font,
8539
// so instead of "Save"/"Revert" you'd use icons!
8540
// Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
8541
SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Save")) { ref->Colors[i] = style.Colors[i]; }
8542
SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
8543
}
8544
SameLine(0.0f, style.ItemInnerSpacing.x);
8545
TextUnformatted(name);
8546
PopID();
8547
}
8548
PopItemWidth();
8549
EndChild();
8550
8551
EndTabItem();
8552
}
8553
8554
if (BeginTabItem("Fonts"))
8555
{
8556
ImGuiIO& io = GetIO();
8557
ImFontAtlas* atlas = io.Fonts;
8558
ShowFontAtlas(atlas);
8559
8560
// Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
8561
// (we enforce hard clamping manually as by default DragFloat/SliderFloat allows Ctrl+Click text to get out of bounds).
8562
/*
8563
SeparatorText("Legacy Scaling");
8564
const float MIN_SCALE = 0.3f;
8565
const float MAX_SCALE = 2.0f;
8566
HelpMarker(
8567
"Those are old settings provided for convenience.\n"
8568
"However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
8569
"rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
8570
"Using those settings here will give you poor quality results.");
8571
PushItemWidth(GetFontSize() * 8);
8572
DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
8573
//static float window_scale = 1.0f;
8574
//if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
8575
// SetWindowFontScale(window_scale);
8576
PopItemWidth();
8577
*/
8578
8579
EndTabItem();
8580
}
8581
8582
if (BeginTabItem("Rendering"))
8583
{
8584
Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
8585
SameLine();
8586
HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
8587
8588
Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
8589
SameLine();
8590
HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
8591
8592
Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
8593
PushItemWidth(GetFontSize() * 8);
8594
DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
8595
if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
8596
8597
// When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
8598
DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
8599
const bool show_samples = IsItemActive();
8600
if (show_samples)
8601
SetNextWindowPos(GetCursorScreenPos());
8602
if (show_samples && BeginTooltip())
8603
{
8604
TextUnformatted("(R = radius, N = approx number of segments)");
8605
Spacing();
8606
ImDrawList* draw_list = GetWindowDrawList();
8607
const float min_widget_width = CalcTextSize("R: MMM\nN: MMM").x;
8608
for (int n = 0; n < 8; n++)
8609
{
8610
const float RAD_MIN = 5.0f;
8611
const float RAD_MAX = 70.0f;
8612
const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
8613
8614
BeginGroup();
8615
8616
// N is not always exact here due to how PathArcTo() function work internally
8617
Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
8618
8619
const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
8620
const float offset_x = floorf(canvas_width * 0.5f);
8621
const float offset_y = floorf(RAD_MAX);
8622
8623
const ImVec2 p1 = GetCursorScreenPos();
8624
draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, GetColorU32(ImGuiCol_Text));
8625
Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8626
8627
/*
8628
const ImVec2 p2 = GetCursorScreenPos();
8629
draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, GetColorU32(ImGuiCol_Text));
8630
Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8631
*/
8632
8633
EndGroup();
8634
SameLine();
8635
}
8636
EndTooltip();
8637
}
8638
SameLine();
8639
HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically.");
8640
8641
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.
8642
DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).");
8643
PopItemWidth();
8644
8645
EndTabItem();
8646
}
8647
8648
EndTabBar();
8649
}
8650
PopItemWidth();
8651
}
8652
8653
//-----------------------------------------------------------------------------
8654
// [SECTION] User Guide / ShowUserGuide()
8655
//-----------------------------------------------------------------------------
8656
8657
// We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code.
8658
void ImGui::ShowUserGuide()
8659
{
8660
ImGuiIO& io = GetIO();
8661
BulletText("Double-click on title bar to collapse window.");
8662
BulletText(
8663
"Click and drag on lower corner or border to resize window.\n"
8664
"(double-click to auto fit window to its contents)");
8665
BulletText("Ctrl+Click on a slider or drag box to input value as text.");
8666
BulletText("Tab/Shift+Tab to cycle through keyboard editable fields.");
8667
BulletText("Ctrl+Tab/Ctrl+Shift+Tab to focus windows.");
8668
if (io.FontAllowUserScaling)
8669
BulletText("Ctrl+Mouse Wheel to zoom window contents.");
8670
BulletText("While inputting text:\n");
8671
Indent();
8672
BulletText("Ctrl+Left/Right to word jump.");
8673
BulletText("Ctrl+A or double-click to select all.");
8674
BulletText("Ctrl+X/C/V to use clipboard cut/copy/paste.");
8675
BulletText("Ctrl+Z to undo, Ctrl+Y/Ctrl+Shift+Z to redo.");
8676
BulletText("Escape to revert.");
8677
Unindent();
8678
BulletText("With keyboard navigation enabled:");
8679
Indent();
8680
BulletText("Arrow keys or Home/End/PageUp/PageDown to navigate.");
8681
BulletText("Space to activate a widget.");
8682
BulletText("Return to input text into a widget.");
8683
BulletText("Escape to deactivate a widget, close popup,\nexit a child window or the menu layer, clear focus.");
8684
BulletText("Alt to jump to the menu layer of a window.");
8685
Unindent();
8686
}
8687
8688
//-----------------------------------------------------------------------------
8689
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
8690
//-----------------------------------------------------------------------------
8691
// - ShowExampleAppMainMenuBar()
8692
// - ShowExampleMenuFile()
8693
//-----------------------------------------------------------------------------
8694
8695
// Demonstrate creating a "main" fullscreen menu bar and populating it.
8696
// Note the difference between BeginMainMenuBar() and BeginMenuBar():
8697
// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
8698
// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
8699
static void ShowExampleAppMainMenuBar()
8700
{
8701
if (ImGui::BeginMainMenuBar())
8702
{
8703
if (ImGui::BeginMenu("File"))
8704
{
8705
ShowExampleMenuFile();
8706
ImGui::EndMenu();
8707
}
8708
if (ImGui::BeginMenu("Edit"))
8709
{
8710
if (ImGui::MenuItem("Undo", "Ctrl+Z")) {}
8711
if (ImGui::MenuItem("Redo", "Ctrl+Y", false, false)) {} // Disabled item
8712
ImGui::Separator();
8713
if (ImGui::MenuItem("Cut", "Ctrl+X")) {}
8714
if (ImGui::MenuItem("Copy", "Ctrl+C")) {}
8715
if (ImGui::MenuItem("Paste", "Ctrl+V")) {}
8716
ImGui::EndMenu();
8717
}
8718
ImGui::EndMainMenuBar();
8719
}
8720
}
8721
8722
// Note that shortcuts are currently provided for display only
8723
// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
8724
static void ShowExampleMenuFile()
8725
{
8726
IMGUI_DEMO_MARKER("Examples/Menu");
8727
ImGui::MenuItem("(demo menu)", NULL, false, false);
8728
if (ImGui::MenuItem("New")) {}
8729
if (ImGui::MenuItem("Open", "Ctrl+O")) {}
8730
if (ImGui::BeginMenu("Open Recent"))
8731
{
8732
ImGui::MenuItem("fish_hat.c");
8733
ImGui::MenuItem("fish_hat.inl");
8734
ImGui::MenuItem("fish_hat.h");
8735
if (ImGui::BeginMenu("More.."))
8736
{
8737
ImGui::MenuItem("Hello");
8738
ImGui::MenuItem("Sailor");
8739
if (ImGui::BeginMenu("Recurse.."))
8740
{
8741
ShowExampleMenuFile();
8742
ImGui::EndMenu();
8743
}
8744
ImGui::EndMenu();
8745
}
8746
ImGui::EndMenu();
8747
}
8748
if (ImGui::MenuItem("Save", "Ctrl+S")) {}
8749
if (ImGui::MenuItem("Save As..")) {}
8750
8751
ImGui::Separator();
8752
IMGUI_DEMO_MARKER("Examples/Menu/Options");
8753
if (ImGui::BeginMenu("Options"))
8754
{
8755
static bool enabled = true;
8756
ImGui::MenuItem("Enabled", "", &enabled);
8757
ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders);
8758
for (int i = 0; i < 10; i++)
8759
ImGui::Text("Scrolling Text %d", i);
8760
ImGui::EndChild();
8761
static float f = 0.5f;
8762
static int n = 0;
8763
ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
8764
ImGui::InputFloat("Input", &f, 0.1f);
8765
ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
8766
ImGui::EndMenu();
8767
}
8768
8769
IMGUI_DEMO_MARKER("Examples/Menu/Colors");
8770
if (ImGui::BeginMenu("Colors"))
8771
{
8772
float sz = ImGui::GetTextLineHeight();
8773
for (int i = 0; i < ImGuiCol_COUNT; i++)
8774
{
8775
const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
8776
ImVec2 p = ImGui::GetCursorScreenPos();
8777
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
8778
ImGui::Dummy(ImVec2(sz, sz));
8779
ImGui::SameLine();
8780
ImGui::MenuItem(name);
8781
}
8782
ImGui::EndMenu();
8783
}
8784
8785
// Here we demonstrate appending again to the "Options" menu (which we already created above)
8786
// Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
8787
// In a real code-base using it would make senses to use this feature from very different code locations.
8788
if (ImGui::BeginMenu("Options")) // <-- Append!
8789
{
8790
IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
8791
static bool b = true;
8792
ImGui::Checkbox("SomeOption", &b);
8793
ImGui::EndMenu();
8794
}
8795
8796
if (ImGui::BeginMenu("Disabled", false)) // Disabled
8797
{
8798
IM_ASSERT(0);
8799
}
8800
if (ImGui::MenuItem("Checked", NULL, true)) {}
8801
ImGui::Separator();
8802
if (ImGui::MenuItem("Quit", "Alt+F4")) {}
8803
}
8804
8805
//-----------------------------------------------------------------------------
8806
// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
8807
//-----------------------------------------------------------------------------
8808
8809
// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
8810
// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
8811
struct ExampleAppConsole
8812
{
8813
char InputBuf[256];
8814
ImVector<char*> Items;
8815
ImVector<const char*> Commands;
8816
ImVector<char*> History;
8817
int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
8818
ImGuiTextFilter Filter;
8819
bool AutoScroll;
8820
bool ScrollToBottom;
8821
8822
ExampleAppConsole()
8823
{
8824
IMGUI_DEMO_MARKER("Examples/Console");
8825
ClearLog();
8826
memset(InputBuf, 0, sizeof(InputBuf));
8827
HistoryPos = -1;
8828
8829
// "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
8830
Commands.push_back("HELP");
8831
Commands.push_back("HISTORY");
8832
Commands.push_back("CLEAR");
8833
Commands.push_back("CLASSIFY");
8834
AutoScroll = true;
8835
ScrollToBottom = false;
8836
AddLog("Welcome to Dear ImGui!");
8837
}
8838
~ExampleAppConsole()
8839
{
8840
ClearLog();
8841
for (int i = 0; i < History.Size; i++)
8842
ImGui::MemFree(History[i]);
8843
}
8844
8845
// Portable helpers
8846
static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
8847
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; }
8848
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); }
8849
static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
8850
8851
void ClearLog()
8852
{
8853
for (int i = 0; i < Items.Size; i++)
8854
ImGui::MemFree(Items[i]);
8855
Items.clear();
8856
}
8857
8858
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
8859
{
8860
// FIXME-OPT
8861
char buf[1024];
8862
va_list args;
8863
va_start(args, fmt);
8864
vsnprintf(buf, IM_COUNTOF(buf), fmt, args);
8865
buf[IM_COUNTOF(buf)-1] = 0;
8866
va_end(args);
8867
Items.push_back(Strdup(buf));
8868
}
8869
8870
void Draw(const char* title, bool* p_open)
8871
{
8872
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
8873
if (!ImGui::Begin(title, p_open))
8874
{
8875
ImGui::End();
8876
return;
8877
}
8878
8879
// As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
8880
// So e.g. IsItemHovered() will return true when hovering the title bar.
8881
// Here we create a context menu only available from the title bar.
8882
if (ImGui::BeginPopupContextItem())
8883
{
8884
if (ImGui::MenuItem("Close Console"))
8885
*p_open = false;
8886
ImGui::EndPopup();
8887
}
8888
8889
ImGui::TextWrapped(
8890
"This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
8891
"implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
8892
ImGui::TextWrapped("Enter 'HELP' for help.");
8893
8894
// TODO: display items starting from the bottom
8895
8896
if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
8897
ImGui::SameLine();
8898
if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
8899
ImGui::SameLine();
8900
if (ImGui::SmallButton("Clear")) { ClearLog(); }
8901
ImGui::SameLine();
8902
bool copy_to_clipboard = ImGui::SmallButton("Copy");
8903
//static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
8904
8905
ImGui::Separator();
8906
8907
// Options menu
8908
if (ImGui::BeginPopup("Options"))
8909
{
8910
ImGui::Checkbox("Auto-scroll", &AutoScroll);
8911
ImGui::EndPopup();
8912
}
8913
8914
// Options, Filter
8915
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_Tooltip);
8916
if (ImGui::Button("Options"))
8917
ImGui::OpenPopup("Options");
8918
ImGui::SameLine();
8919
Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
8920
ImGui::Separator();
8921
8922
// Reserve enough left-over height for 1 separator + 1 input text
8923
const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
8924
if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
8925
{
8926
if (ImGui::BeginPopupContextWindow())
8927
{
8928
if (ImGui::Selectable("Clear")) ClearLog();
8929
ImGui::EndPopup();
8930
}
8931
8932
// Display every line as a separate entry so we can change their color or add custom widgets.
8933
// If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
8934
// NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
8935
// to only process visible items. The clipper will automatically measure the height of your first item and then
8936
// "seek" to display only items in the visible area.
8937
// To use the clipper we can replace your standard loop:
8938
// for (int i = 0; i < Items.Size; i++)
8939
// With:
8940
// ImGuiListClipper clipper;
8941
// clipper.Begin(Items.Size);
8942
// while (clipper.Step())
8943
// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
8944
// - That your items are evenly spaced (same height)
8945
// - That you have cheap random access to your elements (you can access them given their index,
8946
// without processing all the ones before)
8947
// You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
8948
// We would need random-access on the post-filtered list.
8949
// A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
8950
// or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
8951
// and appending newly elements as they are inserted. This is left as a task to the user until we can manage
8952
// to improve this example code!
8953
// If your items are of variable height:
8954
// - Split them into same height items would be simpler and facilitate random-seeking into your list.
8955
// - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
8956
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
8957
if (copy_to_clipboard)
8958
ImGui::LogToClipboard();
8959
for (const char* item : Items)
8960
{
8961
if (!Filter.PassFilter(item))
8962
continue;
8963
8964
// Normally you would store more information in your item than just a string.
8965
// (e.g. make Items[] an array of structure, store color/type etc.)
8966
ImVec4 color;
8967
bool has_color = false;
8968
if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
8969
else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
8970
if (has_color)
8971
ImGui::PushStyleColor(ImGuiCol_Text, color);
8972
ImGui::TextUnformatted(item);
8973
if (has_color)
8974
ImGui::PopStyleColor();
8975
}
8976
if (copy_to_clipboard)
8977
ImGui::LogFinish();
8978
8979
// Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8980
// Using a scrollbar or mouse-wheel will take away from the bottom edge.
8981
if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
8982
ImGui::SetScrollHereY(1.0f);
8983
ScrollToBottom = false;
8984
8985
ImGui::PopStyleVar();
8986
}
8987
ImGui::EndChild();
8988
ImGui::Separator();
8989
8990
// Command-line
8991
bool reclaim_focus = false;
8992
ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
8993
if (ImGui::InputText("Input", InputBuf, IM_COUNTOF(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
8994
{
8995
char* s = InputBuf;
8996
Strtrim(s);
8997
if (s[0])
8998
ExecCommand(s);
8999
strcpy(s, "");
9000
reclaim_focus = true;
9001
}
9002
9003
// Auto-focus on window apparition
9004
ImGui::SetItemDefaultFocus();
9005
if (reclaim_focus)
9006
ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
9007
9008
ImGui::End();
9009
}
9010
9011
void ExecCommand(const char* command_line)
9012
{
9013
AddLog("# %s\n", command_line);
9014
9015
// Insert into history. First find match and delete it so it can be pushed to the back.
9016
// This isn't trying to be smart or optimal.
9017
HistoryPos = -1;
9018
for (int i = History.Size - 1; i >= 0; i--)
9019
if (Stricmp(History[i], command_line) == 0)
9020
{
9021
ImGui::MemFree(History[i]);
9022
History.erase(History.begin() + i);
9023
break;
9024
}
9025
History.push_back(Strdup(command_line));
9026
9027
// Process command
9028
if (Stricmp(command_line, "CLEAR") == 0)
9029
{
9030
ClearLog();
9031
}
9032
else if (Stricmp(command_line, "HELP") == 0)
9033
{
9034
AddLog("Commands:");
9035
for (int i = 0; i < Commands.Size; i++)
9036
AddLog("- %s", Commands[i]);
9037
}
9038
else if (Stricmp(command_line, "HISTORY") == 0)
9039
{
9040
int first = History.Size - 10;
9041
for (int i = first > 0 ? first : 0; i < History.Size; i++)
9042
AddLog("%3d: %s\n", i, History[i]);
9043
}
9044
else
9045
{
9046
AddLog("Unknown command: '%s'\n", command_line);
9047
}
9048
9049
// On command input, we scroll to bottom even if AutoScroll==false
9050
ScrollToBottom = true;
9051
}
9052
9053
// In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
9054
static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
9055
{
9056
ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
9057
return console->TextEditCallback(data);
9058
}
9059
9060
int TextEditCallback(ImGuiInputTextCallbackData* data)
9061
{
9062
//AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
9063
switch (data->EventFlag)
9064
{
9065
case ImGuiInputTextFlags_CallbackCompletion:
9066
{
9067
// Example of TEXT COMPLETION
9068
9069
// Locate beginning of current word
9070
const char* word_end = data->Buf + data->CursorPos;
9071
const char* word_start = word_end;
9072
while (word_start > data->Buf)
9073
{
9074
const char c = word_start[-1];
9075
if (c == ' ' || c == '\t' || c == ',' || c == ';')
9076
break;
9077
word_start--;
9078
}
9079
9080
// Build a list of candidates
9081
ImVector<const char*> candidates;
9082
for (int i = 0; i < Commands.Size; i++)
9083
if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
9084
candidates.push_back(Commands[i]);
9085
9086
if (candidates.Size == 0)
9087
{
9088
// No match
9089
AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
9090
}
9091
else if (candidates.Size == 1)
9092
{
9093
// Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
9094
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
9095
data->InsertChars(data->CursorPos, candidates[0]);
9096
data->InsertChars(data->CursorPos, " ");
9097
}
9098
else
9099
{
9100
// Multiple matches. Complete as much as we can..
9101
// So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
9102
int match_len = (int)(word_end - word_start);
9103
for (;;)
9104
{
9105
int c = 0;
9106
bool all_candidates_matches = true;
9107
for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
9108
if (i == 0)
9109
c = toupper(candidates[i][match_len]);
9110
else if (c == 0 || c != toupper(candidates[i][match_len]))
9111
all_candidates_matches = false;
9112
if (!all_candidates_matches)
9113
break;
9114
match_len++;
9115
}
9116
9117
if (match_len > 0)
9118
{
9119
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
9120
data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
9121
}
9122
9123
// List matches
9124
AddLog("Possible matches:\n");
9125
for (int i = 0; i < candidates.Size; i++)
9126
AddLog("- %s\n", candidates[i]);
9127
}
9128
9129
break;
9130
}
9131
case ImGuiInputTextFlags_CallbackHistory:
9132
{
9133
// Example of HISTORY
9134
const int prev_history_pos = HistoryPos;
9135
if (data->EventKey == ImGuiKey_UpArrow)
9136
{
9137
if (HistoryPos == -1)
9138
HistoryPos = History.Size - 1;
9139
else if (HistoryPos > 0)
9140
HistoryPos--;
9141
}
9142
else if (data->EventKey == ImGuiKey_DownArrow)
9143
{
9144
if (HistoryPos != -1)
9145
if (++HistoryPos >= History.Size)
9146
HistoryPos = -1;
9147
}
9148
9149
// A better implementation would preserve the data on the current input line along with cursor position.
9150
if (prev_history_pos != HistoryPos)
9151
{
9152
const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
9153
data->DeleteChars(0, data->BufTextLen);
9154
data->InsertChars(0, history_str);
9155
}
9156
}
9157
}
9158
return 0;
9159
}
9160
};
9161
9162
static void ShowExampleAppConsole(bool* p_open)
9163
{
9164
static ExampleAppConsole console;
9165
console.Draw("Example: Console", p_open);
9166
}
9167
9168
//-----------------------------------------------------------------------------
9169
// [SECTION] Example App: Debug Log / ShowExampleAppLog()
9170
//-----------------------------------------------------------------------------
9171
9172
// Usage:
9173
// static ExampleAppLog my_log;
9174
// my_log.AddLog("Hello %d world\n", 123);
9175
// my_log.Draw("title");
9176
struct ExampleAppLog
9177
{
9178
ImGuiTextBuffer Buf;
9179
ImGuiTextFilter Filter;
9180
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
9181
bool AutoScroll; // Keep scrolling if already at the bottom.
9182
9183
ExampleAppLog()
9184
{
9185
AutoScroll = true;
9186
Clear();
9187
}
9188
9189
void Clear()
9190
{
9191
Buf.clear();
9192
LineOffsets.clear();
9193
LineOffsets.push_back(0);
9194
}
9195
9196
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
9197
{
9198
int old_size = Buf.size();
9199
va_list args;
9200
va_start(args, fmt);
9201
Buf.appendfv(fmt, args);
9202
va_end(args);
9203
for (int new_size = Buf.size(); old_size < new_size; old_size++)
9204
if (Buf[old_size] == '\n')
9205
LineOffsets.push_back(old_size + 1);
9206
}
9207
9208
void Draw(const char* title, bool* p_open = NULL)
9209
{
9210
if (!ImGui::Begin(title, p_open))
9211
{
9212
ImGui::End();
9213
return;
9214
}
9215
9216
// Options menu
9217
if (ImGui::BeginPopup("Options"))
9218
{
9219
ImGui::Checkbox("Auto-scroll", &AutoScroll);
9220
ImGui::EndPopup();
9221
}
9222
9223
// Main window
9224
if (ImGui::Button("Options"))
9225
ImGui::OpenPopup("Options");
9226
ImGui::SameLine();
9227
bool clear = ImGui::Button("Clear");
9228
ImGui::SameLine();
9229
bool copy = ImGui::Button("Copy");
9230
ImGui::SameLine();
9231
Filter.Draw("Filter", -100.0f);
9232
9233
ImGui::Separator();
9234
9235
if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
9236
{
9237
if (clear)
9238
Clear();
9239
if (copy)
9240
ImGui::LogToClipboard();
9241
9242
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9243
const char* buf = Buf.begin();
9244
const char* buf_end = Buf.end();
9245
if (Filter.IsActive())
9246
{
9247
// In this example we don't use the clipper when Filter is enabled.
9248
// This is because we don't have random access to the result of our filter.
9249
// A real application processing logs with ten of thousands of entries may want to store the result of
9250
// search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
9251
for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
9252
{
9253
const char* line_start = buf + LineOffsets[line_no];
9254
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
9255
if (Filter.PassFilter(line_start, line_end))
9256
ImGui::TextUnformatted(line_start, line_end);
9257
}
9258
}
9259
else
9260
{
9261
// The simplest and easy way to display the entire buffer:
9262
// ImGui::TextUnformatted(buf_begin, buf_end);
9263
// And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
9264
// to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
9265
// within the visible area.
9266
// If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
9267
// on your side is recommended. Using ImGuiListClipper requires
9268
// - A) random access into your data
9269
// - B) items all being the same height,
9270
// both of which we can handle since we have an array pointing to the beginning of each line of text.
9271
// When using the filter (in the block of code above) we don't have random access into the data to display
9272
// anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
9273
// it possible (and would be recommended if you want to search through tens of thousands of entries).
9274
ImGuiListClipper clipper;
9275
clipper.Begin(LineOffsets.Size);
9276
while (clipper.Step())
9277
{
9278
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
9279
{
9280
const char* line_start = buf + LineOffsets[line_no];
9281
const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
9282
ImGui::TextUnformatted(line_start, line_end);
9283
}
9284
}
9285
clipper.End();
9286
}
9287
ImGui::PopStyleVar();
9288
9289
// Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
9290
// Using a scrollbar or mouse-wheel will take away from the bottom edge.
9291
if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
9292
ImGui::SetScrollHereY(1.0f);
9293
}
9294
ImGui::EndChild();
9295
ImGui::End();
9296
}
9297
};
9298
9299
// Demonstrate creating a simple log window with basic filtering.
9300
static void ShowExampleAppLog(bool* p_open)
9301
{
9302
static ExampleAppLog log;
9303
9304
// For the demo: add a debug button _BEFORE_ the normal log window contents
9305
// We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
9306
// Most of the contents of the window will be added by the log.Draw() call.
9307
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
9308
ImGui::Begin("Example: Log", p_open);
9309
IMGUI_DEMO_MARKER("Examples/Log");
9310
if (ImGui::SmallButton("[Debug] Add 5 entries"))
9311
{
9312
static int counter = 0;
9313
const char* categories[3] = { "info", "warn", "error" };
9314
const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
9315
for (int n = 0; n < 5; n++)
9316
{
9317
const char* category = categories[counter % IM_COUNTOF(categories)];
9318
const char* word = words[counter % IM_COUNTOF(words)];
9319
log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
9320
ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
9321
counter++;
9322
}
9323
}
9324
ImGui::End();
9325
9326
// Actually call in the regular Log helper (which will Begin() into the same window as we just did)
9327
log.Draw("Example: Log", p_open);
9328
}
9329
9330
//-----------------------------------------------------------------------------
9331
// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
9332
//-----------------------------------------------------------------------------
9333
9334
// Demonstrate create a window with multiple child windows.
9335
static void ShowExampleAppLayout(bool* p_open)
9336
{
9337
ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
9338
if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
9339
{
9340
IMGUI_DEMO_MARKER("Examples/Simple layout");
9341
if (ImGui::BeginMenuBar())
9342
{
9343
if (ImGui::BeginMenu("File"))
9344
{
9345
if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; }
9346
ImGui::EndMenu();
9347
}
9348
ImGui::EndMenuBar();
9349
}
9350
9351
// Left
9352
static int selected = 0;
9353
{
9354
ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
9355
for (int i = 0; i < 100; i++)
9356
{
9357
char label[128];
9358
sprintf(label, "MyObject %d", i);
9359
if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SelectOnNav))
9360
selected = i;
9361
}
9362
ImGui::EndChild();
9363
}
9364
ImGui::SameLine();
9365
9366
// Right
9367
{
9368
ImGui::BeginGroup();
9369
ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
9370
ImGui::Text("MyObject: %d", selected);
9371
ImGui::Separator();
9372
if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
9373
{
9374
if (ImGui::BeginTabItem("Description"))
9375
{
9376
ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
9377
ImGui::EndTabItem();
9378
}
9379
if (ImGui::BeginTabItem("Details"))
9380
{
9381
ImGui::Text("ID: 0123456789");
9382
ImGui::EndTabItem();
9383
}
9384
ImGui::EndTabBar();
9385
}
9386
ImGui::EndChild();
9387
if (ImGui::Button("Revert")) {}
9388
ImGui::SameLine();
9389
if (ImGui::Button("Save")) {}
9390
ImGui::EndGroup();
9391
}
9392
}
9393
ImGui::End();
9394
}
9395
9396
//-----------------------------------------------------------------------------
9397
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
9398
//-----------------------------------------------------------------------------
9399
// Some of the interactions are a bit lack-luster:
9400
// - We would want pressing validating or leaving the filter to somehow restore focus.
9401
// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
9402
// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
9403
//-----------------------------------------------------------------------------
9404
9405
struct ExampleAppPropertyEditor
9406
{
9407
ImGuiTextFilter Filter;
9408
ExampleTreeNode* VisibleNode = NULL;
9409
9410
void Draw(ExampleTreeNode* root_node)
9411
{
9412
// Left side: draw tree
9413
// - Currently using a table to benefit from RowBg feature
9414
if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
9415
{
9416
ImGui::SetNextItemWidth(-FLT_MIN);
9417
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
9418
ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
9419
if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
9420
Filter.Build();
9421
ImGui::PopItemFlag();
9422
9423
if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg))
9424
{
9425
for (ExampleTreeNode* node : root_node->Childs)
9426
if (Filter.PassFilter(node->Name)) // Filter root node
9427
DrawTreeNode(node);
9428
ImGui::EndTable();
9429
}
9430
}
9431
ImGui::EndChild();
9432
9433
// Right side: draw properties
9434
ImGui::SameLine();
9435
9436
ImGui::BeginGroup(); // Lock X position
9437
if (ExampleTreeNode* node = VisibleNode)
9438
{
9439
ImGui::Text("%s", node->Name);
9440
ImGui::TextDisabled("UID: 0x%08X", node->UID);
9441
ImGui::Separator();
9442
if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
9443
{
9444
// Push object ID after we entered the table, so table is shared for all objects
9445
ImGui::PushID((int)node->UID);
9446
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
9447
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
9448
if (node->HasData)
9449
{
9450
// In a typical application, the structure description would be derived from a data-driven system.
9451
// - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
9452
// - Limits and some details are hard-coded to simplify the demo.
9453
for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
9454
{
9455
ImGui::TableNextRow();
9456
ImGui::PushID(field_desc.Name);
9457
ImGui::TableNextColumn();
9458
ImGui::AlignTextToFramePadding();
9459
ImGui::TextUnformatted(field_desc.Name);
9460
ImGui::TableNextColumn();
9461
void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
9462
switch (field_desc.DataType)
9463
{
9464
case ImGuiDataType_Bool:
9465
{
9466
IM_ASSERT(field_desc.DataCount == 1);
9467
ImGui::Checkbox("##Editor", (bool*)field_ptr);
9468
break;
9469
}
9470
case ImGuiDataType_S32:
9471
{
9472
int v_min = INT_MIN, v_max = INT_MAX;
9473
ImGui::SetNextItemWidth(-FLT_MIN);
9474
ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
9475
break;
9476
}
9477
case ImGuiDataType_Float:
9478
{
9479
float v_min = 0.0f, v_max = 1.0f;
9480
ImGui::SetNextItemWidth(-FLT_MIN);
9481
ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
9482
break;
9483
}
9484
case ImGuiDataType_String:
9485
{
9486
ImGui::InputText("##Editor", reinterpret_cast<char*>(field_ptr), 28);
9487
break;
9488
}
9489
}
9490
ImGui::PopID();
9491
}
9492
}
9493
ImGui::PopID();
9494
ImGui::EndTable();
9495
}
9496
}
9497
ImGui::EndGroup();
9498
}
9499
9500
void DrawTreeNode(ExampleTreeNode* node)
9501
{
9502
ImGui::TableNextRow();
9503
ImGui::TableNextColumn();
9504
ImGui::PushID(node->UID);
9505
ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
9506
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;// Standard opening mode as we are likely to want to add selection afterwards
9507
tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Left arrow support
9508
tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth; // Span full width for easier mouse reach
9509
tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes; // Always draw hierarchy outlines
9510
if (node == VisibleNode)
9511
tree_flags |= ImGuiTreeNodeFlags_Selected;
9512
if (node->Childs.Size == 0)
9513
tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
9514
if (node->DataMyBool == false)
9515
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
9516
bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
9517
if (node->DataMyBool == false)
9518
ImGui::PopStyleColor();
9519
if (ImGui::IsItemFocused())
9520
VisibleNode = node;
9521
if (node_open)
9522
{
9523
for (ExampleTreeNode* child : node->Childs)
9524
DrawTreeNode(child);
9525
ImGui::TreePop();
9526
}
9527
ImGui::PopID();
9528
}
9529
};
9530
9531
// Demonstrate creating a simple property editor.
9532
static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data)
9533
{
9534
ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
9535
if (!ImGui::Begin("Example: Property editor", p_open))
9536
{
9537
ImGui::End();
9538
return;
9539
}
9540
9541
IMGUI_DEMO_MARKER("Examples/Property Editor");
9542
static ExampleAppPropertyEditor property_editor;
9543
if (demo_data->DemoTree == NULL)
9544
demo_data->DemoTree = ExampleTree_CreateDemoTree();
9545
property_editor.Draw(demo_data->DemoTree);
9546
9547
ImGui::End();
9548
}
9549
9550
//-----------------------------------------------------------------------------
9551
// [SECTION] Example App: Long Text / ShowExampleAppLongText()
9552
//-----------------------------------------------------------------------------
9553
9554
// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
9555
static void ShowExampleAppLongText(bool* p_open)
9556
{
9557
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
9558
if (!ImGui::Begin("Example: Long text display", p_open))
9559
{
9560
ImGui::End();
9561
return;
9562
}
9563
IMGUI_DEMO_MARKER("Examples/Long text display");
9564
9565
static int test_type = 0;
9566
static ImGuiTextBuffer log;
9567
static int lines = 0;
9568
ImGui::Text("Printing unusually long amount of text.");
9569
ImGui::Combo("Test type", &test_type,
9570
"Single call to TextUnformatted()\0"
9571
"Multiple calls to Text(), clipped\0"
9572
"Multiple calls to Text(), not clipped (slow)\0");
9573
ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
9574
if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
9575
ImGui::SameLine();
9576
if (ImGui::Button("Add 1000 lines"))
9577
{
9578
for (int i = 0; i < 1000; i++)
9579
log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
9580
lines += 1000;
9581
}
9582
ImGui::BeginChild("Log");
9583
switch (test_type)
9584
{
9585
case 0:
9586
// Single call to TextUnformatted() with a big buffer
9587
ImGui::TextUnformatted(log.begin(), log.end());
9588
break;
9589
case 1:
9590
{
9591
// Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
9592
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9593
ImGuiListClipper clipper;
9594
clipper.Begin(lines);
9595
while (clipper.Step())
9596
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
9597
ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9598
ImGui::PopStyleVar();
9599
break;
9600
}
9601
case 2:
9602
// Multiple calls to Text(), not clipped (slow)
9603
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9604
for (int i = 0; i < lines; i++)
9605
ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9606
ImGui::PopStyleVar();
9607
break;
9608
}
9609
ImGui::EndChild();
9610
ImGui::End();
9611
}
9612
9613
//-----------------------------------------------------------------------------
9614
// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
9615
//-----------------------------------------------------------------------------
9616
9617
// Demonstrate creating a window which gets auto-resized according to its content.
9618
static void ShowExampleAppAutoResize(bool* p_open)
9619
{
9620
if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
9621
{
9622
ImGui::End();
9623
return;
9624
}
9625
IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
9626
9627
static int lines = 10;
9628
ImGui::TextUnformatted(
9629
"Window will resize every-frame to the size of its content.\n"
9630
"Note that you probably don't want to query the window size to\n"
9631
"output your content because that would create a feedback loop.");
9632
ImGui::SliderInt("Number of lines", &lines, 1, 20);
9633
for (int i = 0; i < lines; i++)
9634
ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
9635
ImGui::End();
9636
}
9637
9638
//-----------------------------------------------------------------------------
9639
// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
9640
//-----------------------------------------------------------------------------
9641
9642
// Demonstrate creating a window with custom resize constraints.
9643
// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
9644
static void ShowExampleAppConstrainedResize(bool* p_open)
9645
{
9646
struct CustomConstraints
9647
{
9648
// Helper functions to demonstrate programmatic constraints
9649
// FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
9650
// FIXME: None of the three demos works consistently when resizing from borders.
9651
static void AspectRatio(ImGuiSizeCallbackData* data)
9652
{
9653
float aspect_ratio = *(float*)data->UserData;
9654
data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
9655
}
9656
static void Square(ImGuiSizeCallbackData* data)
9657
{
9658
data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
9659
}
9660
static void Step(ImGuiSizeCallbackData* data)
9661
{
9662
float step = *(float*)data->UserData;
9663
data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
9664
}
9665
};
9666
9667
const char* test_desc[] =
9668
{
9669
"Between 100x100 and 500x500",
9670
"At least 100x100",
9671
"Resize vertical + lock current width",
9672
"Resize horizontal + lock current height",
9673
"Width Between 400 and 500",
9674
"Height at least 400",
9675
"Custom: Aspect Ratio 16:9",
9676
"Custom: Always Square",
9677
"Custom: Fixed Steps (100)",
9678
};
9679
9680
// Options
9681
static bool auto_resize = false;
9682
static bool window_padding = true;
9683
static int type = 6; // Aspect Ratio
9684
static int display_lines = 10;
9685
9686
// Submit constraint
9687
float aspect_ratio = 16.0f / 9.0f;
9688
float fixed_step = 100.0f;
9689
if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500
9690
if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
9691
if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width
9692
if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height
9693
if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500
9694
if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)); // Height at least 400
9695
if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio
9696
if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
9697
if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step
9698
9699
// Submit window
9700
if (!window_padding)
9701
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9702
const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
9703
const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
9704
if (!window_padding)
9705
ImGui::PopStyleVar();
9706
if (window_open)
9707
{
9708
IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
9709
if (ImGui::GetIO().KeyShift)
9710
{
9711
// Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture)
9712
ImVec2 avail_size = ImGui::GetContentRegionAvail();
9713
ImVec2 pos = ImGui::GetCursorScreenPos();
9714
ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
9715
ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
9716
ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
9717
}
9718
else
9719
{
9720
ImGui::Text("(Hold Shift to display a dummy viewport)");
9721
if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
9722
if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
9723
if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
9724
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9725
ImGui::Combo("Constraint", &type, test_desc, IM_COUNTOF(test_desc));
9726
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9727
ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
9728
ImGui::Checkbox("Auto-resize", &auto_resize);
9729
ImGui::Checkbox("Window padding", &window_padding);
9730
for (int i = 0; i < display_lines; i++)
9731
ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
9732
}
9733
}
9734
ImGui::End();
9735
}
9736
9737
//-----------------------------------------------------------------------------
9738
// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
9739
//-----------------------------------------------------------------------------
9740
9741
// Demonstrate creating a simple static window with no decoration
9742
// + a context-menu to choose which corner of the screen to use.
9743
static void ShowExampleAppSimpleOverlay(bool* p_open)
9744
{
9745
static int location = 0;
9746
ImGuiIO& io = ImGui::GetIO();
9747
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
9748
if (location >= 0)
9749
{
9750
const float PAD = 10.0f;
9751
const ImGuiViewport* viewport = ImGui::GetMainViewport();
9752
ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
9753
ImVec2 work_size = viewport->WorkSize;
9754
ImVec2 window_pos, window_pos_pivot;
9755
window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
9756
window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
9757
window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
9758
window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
9759
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
9760
window_flags |= ImGuiWindowFlags_NoMove;
9761
}
9762
else if (location == -2)
9763
{
9764
// Center window
9765
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
9766
window_flags |= ImGuiWindowFlags_NoMove;
9767
}
9768
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
9769
if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
9770
{
9771
IMGUI_DEMO_MARKER("Examples/Simple Overlay");
9772
ImGui::Text("Simple overlay\n" "(right-click to change position)");
9773
ImGui::Separator();
9774
if (ImGui::IsMousePosValid())
9775
ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
9776
else
9777
ImGui::Text("Mouse Position: <invalid>");
9778
if (ImGui::BeginPopupContextWindow())
9779
{
9780
if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1;
9781
if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2;
9782
if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0;
9783
if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1;
9784
if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2;
9785
if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
9786
if (p_open && ImGui::MenuItem("Close")) *p_open = false;
9787
ImGui::EndPopup();
9788
}
9789
}
9790
ImGui::End();
9791
}
9792
9793
//-----------------------------------------------------------------------------
9794
// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
9795
//-----------------------------------------------------------------------------
9796
9797
// Demonstrate creating a window covering the entire screen/viewport
9798
static void ShowExampleAppFullscreen(bool* p_open)
9799
{
9800
static bool use_work_area = true;
9801
static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
9802
9803
// We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
9804
// Based on your use case you may want one or the other.
9805
const ImGuiViewport* viewport = ImGui::GetMainViewport();
9806
ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
9807
ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
9808
9809
if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
9810
{
9811
ImGui::Checkbox("Use work area instead of main area", &use_work_area);
9812
ImGui::SameLine();
9813
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.");
9814
9815
ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
9816
ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
9817
ImGui::Indent();
9818
ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
9819
ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
9820
ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
9821
ImGui::Unindent();
9822
9823
if (p_open && ImGui::Button("Close this window"))
9824
*p_open = false;
9825
}
9826
ImGui::End();
9827
}
9828
9829
//-----------------------------------------------------------------------------
9830
// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
9831
//-----------------------------------------------------------------------------
9832
9833
// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
9834
// This applies to all regular items as well.
9835
// Read FAQ section "How can I have multiple widgets with the same label?" for details.
9836
static void ShowExampleAppWindowTitles(bool*)
9837
{
9838
const ImGuiViewport* viewport = ImGui::GetMainViewport();
9839
const ImVec2 base_pos = viewport->Pos;
9840
9841
// By default, Windows are uniquely identified by their title.
9842
// You can use the "##" and "###" markers to manipulate the display/ID.
9843
9844
// Using "##" to display same title but have unique identifier.
9845
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
9846
ImGui::Begin("Same title as another window##1");
9847
IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
9848
ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
9849
ImGui::End();
9850
9851
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
9852
ImGui::Begin("Same title as another window##2");
9853
ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
9854
ImGui::End();
9855
9856
// Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
9857
char buf[128];
9858
sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
9859
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
9860
ImGui::Begin(buf);
9861
ImGui::Text("This window has a changing title.");
9862
ImGui::End();
9863
}
9864
9865
//-----------------------------------------------------------------------------
9866
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
9867
//-----------------------------------------------------------------------------
9868
9869
// Add a |_| looking shape
9870
static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
9871
{
9872
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 } };
9873
for (const ImVec2& p : pos_norms)
9874
draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
9875
}
9876
9877
// Demonstrate using the low-level ImDrawList to draw custom shapes.
9878
static void ShowExampleAppCustomRendering(bool* p_open)
9879
{
9880
if (!ImGui::Begin("Example: Custom rendering", p_open))
9881
{
9882
ImGui::End();
9883
return;
9884
}
9885
IMGUI_DEMO_MARKER("Examples/Custom Rendering");
9886
9887
// Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
9888
// overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
9889
// types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
9890
// exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
9891
9892
if (ImGui::BeginTabBar("##TabBar"))
9893
{
9894
if (ImGui::BeginTabItem("Primitives"))
9895
{
9896
ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
9897
ImDrawList* draw_list = ImGui::GetWindowDrawList();
9898
9899
// Draw gradients
9900
// (note that those are currently exacerbating our sRGB/Linear issues)
9901
// Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
9902
ImGui::Text("Gradients");
9903
ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
9904
{
9905
ImVec2 p0 = ImGui::GetCursorScreenPos();
9906
ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9907
ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
9908
ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
9909
draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9910
ImGui::InvisibleButton("##gradient1", gradient_size);
9911
}
9912
{
9913
ImVec2 p0 = ImGui::GetCursorScreenPos();
9914
ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9915
ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
9916
ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
9917
draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9918
ImGui::InvisibleButton("##gradient2", gradient_size);
9919
}
9920
9921
// Draw a bunch of primitives
9922
ImGui::Text("All primitives");
9923
static float sz = 36.0f;
9924
static float thickness = 3.0f;
9925
static int ngon_sides = 6;
9926
static bool circle_segments_override = false;
9927
static int circle_segments_override_v = 12;
9928
static bool curve_segments_override = false;
9929
static int curve_segments_override_v = 8;
9930
static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
9931
ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
9932
ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
9933
ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
9934
ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
9935
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9936
circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
9937
ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
9938
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9939
curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
9940
ImGui::ColorEdit4("Color", &colf.x);
9941
9942
const ImVec2 p = ImGui::GetCursorScreenPos();
9943
const ImU32 col = ImColor(colf);
9944
const float spacing = 10.0f;
9945
const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
9946
const float rounding = sz / 5.0f;
9947
const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
9948
const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
9949
const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
9950
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) };
9951
9952
float x = p.x + 4.0f;
9953
float y = p.y + 4.0f;
9954
for (int n = 0; n < 2; n++)
9955
{
9956
// First line uses a thickness of 1.0f, second line uses the configurable thickness
9957
float th = (n == 0) ? 1.0f : thickness;
9958
draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
9959
draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
9960
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
9961
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
9962
draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
9963
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
9964
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
9965
//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
9966
PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape
9967
//draw_list->AddPolyline(concave_shape, IM_COUNTOF(concave_shape), col, ImDrawFlags_Closed, th);
9968
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!)
9969
draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
9970
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
9971
9972
// Path
9973
draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
9974
draw_list->PathStroke(col, ImDrawFlags_None, th);
9975
x += sz + spacing;
9976
9977
// Quadratic Bezier Curve (3 control points)
9978
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);
9979
x += sz + spacing;
9980
9981
// Cubic Bezier Curve (4 control points)
9982
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);
9983
9984
x = p.x + 4;
9985
y += sz + spacing;
9986
}
9987
9988
// Filled shapes
9989
draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon
9990
draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle
9991
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
9992
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
9993
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners
9994
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
9995
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
9996
//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
9997
PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape
9998
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)
9999
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)
10000
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
10001
10002
// Path
10003
draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f);
10004
draw_list->PathFillConvex(col);
10005
x += sz + spacing;
10006
10007
// Quadratic Bezier Curve (3 control points)
10008
draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y));
10009
draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments);
10010
draw_list->PathFillConvex(col);
10011
x += sz + spacing;
10012
10013
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));
10014
x += sz + spacing;
10015
10016
ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
10017
ImGui::PopItemWidth();
10018
ImGui::EndTabItem();
10019
}
10020
10021
if (ImGui::BeginTabItem("Canvas"))
10022
{
10023
static ImVector<ImVec2> points;
10024
static ImVec2 scrolling(0.0f, 0.0f);
10025
static bool opt_enable_grid = true;
10026
static bool opt_enable_context_menu = true;
10027
static bool adding_line = false;
10028
10029
ImGui::Checkbox("Enable grid", &opt_enable_grid);
10030
ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
10031
ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
10032
10033
// Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
10034
// Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
10035
// To use a child window instead we could use, e.g:
10036
// ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
10037
// ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
10038
// ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove);
10039
// ImGui::PopStyleColor();
10040
// ImGui::PopStyleVar();
10041
// [...]
10042
// ImGui::EndChild();
10043
10044
// Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
10045
ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
10046
ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
10047
if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
10048
if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
10049
ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
10050
10051
// Draw border and background color
10052
ImGuiIO& io = ImGui::GetIO();
10053
ImDrawList* draw_list = ImGui::GetWindowDrawList();
10054
draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
10055
draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
10056
10057
// This will catch our interactions
10058
ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
10059
const bool is_hovered = ImGui::IsItemHovered(); // Hovered
10060
const bool is_active = ImGui::IsItemActive(); // Held
10061
const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
10062
const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
10063
10064
// Add first and second point
10065
if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
10066
{
10067
points.push_back(mouse_pos_in_canvas);
10068
points.push_back(mouse_pos_in_canvas);
10069
adding_line = true;
10070
}
10071
if (adding_line)
10072
{
10073
points.back() = mouse_pos_in_canvas;
10074
if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
10075
adding_line = false;
10076
}
10077
10078
// Pan (we use a zero mouse threshold when there's no context menu)
10079
// You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
10080
const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
10081
if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
10082
{
10083
scrolling.x += io.MouseDelta.x;
10084
scrolling.y += io.MouseDelta.y;
10085
}
10086
10087
// Context menu (under default mouse threshold)
10088
ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
10089
if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
10090
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
10091
if (ImGui::BeginPopup("context"))
10092
{
10093
if (adding_line)
10094
points.resize(points.size() - 2);
10095
adding_line = false;
10096
if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
10097
if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
10098
ImGui::EndPopup();
10099
}
10100
10101
// Draw grid + all lines in the canvas
10102
draw_list->PushClipRect(canvas_p0, canvas_p1, true);
10103
if (opt_enable_grid)
10104
{
10105
const float GRID_STEP = 64.0f;
10106
for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
10107
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));
10108
for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
10109
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));
10110
}
10111
for (int n = 0; n < points.Size; n += 2)
10112
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);
10113
draw_list->PopClipRect();
10114
10115
ImGui::EndTabItem();
10116
}
10117
10118
if (ImGui::BeginTabItem("BG/FG draw lists"))
10119
{
10120
static bool draw_bg = true;
10121
static bool draw_fg = true;
10122
ImGui::Checkbox("Draw in Background draw list", &draw_bg);
10123
ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
10124
ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
10125
ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
10126
ImVec2 window_pos = ImGui::GetWindowPos();
10127
ImVec2 window_size = ImGui::GetWindowSize();
10128
ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
10129
if (draw_bg)
10130
ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
10131
if (draw_fg)
10132
ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
10133
ImGui::EndTabItem();
10134
}
10135
10136
// Demonstrate out-of-order rendering via channels splitting
10137
// We use functions in ImDrawList as each draw list contains a convenience splitter,
10138
// but you can also instantiate your own ImDrawListSplitter if you need to nest them.
10139
if (ImGui::BeginTabItem("Draw Channels"))
10140
{
10141
ImDrawList* draw_list = ImGui::GetWindowDrawList();
10142
{
10143
ImGui::Text("Blue shape is drawn first: appears in back");
10144
ImGui::Text("Red shape is drawn after: appears in front");
10145
ImVec2 p0 = ImGui::GetCursorScreenPos();
10146
draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
10147
draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
10148
ImGui::Dummy(ImVec2(75, 75));
10149
}
10150
ImGui::Separator();
10151
{
10152
ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
10153
ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
10154
ImVec2 p1 = ImGui::GetCursorScreenPos();
10155
10156
// Create 2 channels and draw a Blue shape THEN a Red shape.
10157
// You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
10158
draw_list->ChannelsSplit(2);
10159
draw_list->ChannelsSetCurrent(1);
10160
draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
10161
draw_list->ChannelsSetCurrent(0);
10162
draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
10163
10164
// Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
10165
// This works by copying draw indices only (vertices are not copied).
10166
draw_list->ChannelsMerge();
10167
ImGui::Dummy(ImVec2(75, 75));
10168
ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
10169
}
10170
ImGui::EndTabItem();
10171
}
10172
10173
ImGui::EndTabBar();
10174
}
10175
10176
ImGui::End();
10177
}
10178
10179
//-----------------------------------------------------------------------------
10180
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
10181
//-----------------------------------------------------------------------------
10182
10183
// Simplified structure to mimic a Document model
10184
struct MyDocument
10185
{
10186
char Name[32]; // Document title
10187
int UID; // Unique ID (necessary as we can change title)
10188
bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
10189
bool OpenPrev; // Copy of Open from last update.
10190
bool Dirty; // Set when the document has been modified
10191
ImVec4 Color; // An arbitrary variable associated to the document
10192
10193
MyDocument(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
10194
{
10195
UID = uid;
10196
snprintf(Name, sizeof(Name), "%s", name);
10197
Open = OpenPrev = open;
10198
Dirty = false;
10199
Color = color;
10200
}
10201
void DoOpen() { Open = true; }
10202
void DoForceClose() { Open = false; Dirty = false; }
10203
void DoSave() { Dirty = false; }
10204
};
10205
10206
struct ExampleAppDocuments
10207
{
10208
ImVector<MyDocument> Documents;
10209
ImVector<MyDocument*> CloseQueue;
10210
MyDocument* RenamingDoc = NULL;
10211
bool RenamingStarted = false;
10212
10213
ExampleAppDocuments()
10214
{
10215
Documents.push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
10216
Documents.push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
10217
Documents.push_back(MyDocument(2, "Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
10218
Documents.push_back(MyDocument(3, "Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
10219
Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f)));
10220
Documents.push_back(MyDocument(5, "Some Document", false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f)));
10221
}
10222
10223
// As we allow to change document name, we append a never-changing document ID so tabs are stable
10224
void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size)
10225
{
10226
snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID);
10227
}
10228
10229
// Display placeholder contents for the Document
10230
void DisplayDocContents(MyDocument* doc)
10231
{
10232
ImGui::PushID(doc);
10233
ImGui::Text("Document \"%s\"", doc->Name);
10234
ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
10235
ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
10236
ImGui::PopStyleColor();
10237
10238
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip);
10239
if (ImGui::Button("Rename.."))
10240
{
10241
RenamingDoc = doc;
10242
RenamingStarted = true;
10243
}
10244
ImGui::SameLine();
10245
10246
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_M, ImGuiInputFlags_Tooltip);
10247
if (ImGui::Button("Modify"))
10248
doc->Dirty = true;
10249
10250
ImGui::SameLine();
10251
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
10252
if (ImGui::Button("Save"))
10253
doc->DoSave();
10254
10255
ImGui::SameLine();
10256
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip);
10257
if (ImGui::Button("Close"))
10258
CloseQueue.push_back(doc);
10259
ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
10260
ImGui::PopID();
10261
}
10262
10263
// Display context menu for the Document
10264
void DisplayDocContextMenu(MyDocument* doc)
10265
{
10266
if (!ImGui::BeginPopupContextItem())
10267
return;
10268
10269
char buf[256];
10270
sprintf(buf, "Save %s", doc->Name);
10271
if (ImGui::MenuItem(buf, "Ctrl+S", false, doc->Open))
10272
doc->DoSave();
10273
if (ImGui::MenuItem("Rename...", "Ctrl+R", false, doc->Open))
10274
RenamingDoc = doc;
10275
if (ImGui::MenuItem("Close", "Ctrl+W", false, doc->Open))
10276
CloseQueue.push_back(doc);
10277
ImGui::EndPopup();
10278
}
10279
10280
// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
10281
// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
10282
// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
10283
// 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
10284
// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
10285
// give the impression of a flicker for one frame.
10286
// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
10287
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
10288
void NotifyOfDocumentsClosedElsewhere()
10289
{
10290
for (MyDocument& doc : Documents)
10291
{
10292
if (!doc.Open && doc.OpenPrev)
10293
ImGui::SetTabItemClosed(doc.Name);
10294
doc.OpenPrev = doc.Open;
10295
}
10296
}
10297
};
10298
10299
void ShowExampleAppDocuments(bool* p_open)
10300
{
10301
static ExampleAppDocuments app;
10302
10303
// Options
10304
static bool opt_reorderable = true;
10305
static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
10306
10307
bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
10308
if (!window_contents_visible)
10309
{
10310
ImGui::End();
10311
return;
10312
}
10313
10314
// Menu
10315
if (ImGui::BeginMenuBar())
10316
{
10317
if (ImGui::BeginMenu("File"))
10318
{
10319
int open_count = 0;
10320
for (MyDocument& doc : app.Documents)
10321
open_count += doc.Open ? 1 : 0;
10322
10323
if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
10324
{
10325
for (MyDocument& doc : app.Documents)
10326
if (!doc.Open && ImGui::MenuItem(doc.Name))
10327
doc.DoOpen();
10328
ImGui::EndMenu();
10329
}
10330
if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
10331
for (MyDocument& doc : app.Documents)
10332
app.CloseQueue.push_back(&doc);
10333
if (ImGui::MenuItem("Exit") && p_open)
10334
*p_open = false;
10335
ImGui::EndMenu();
10336
}
10337
ImGui::EndMenuBar();
10338
}
10339
10340
// [Debug] List documents with one checkbox for each
10341
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10342
{
10343
MyDocument& doc = app.Documents[doc_n];
10344
if (doc_n > 0)
10345
ImGui::SameLine();
10346
ImGui::PushID(&doc);
10347
if (ImGui::Checkbox(doc.Name, &doc.Open))
10348
if (!doc.Open)
10349
doc.DoForceClose();
10350
ImGui::PopID();
10351
}
10352
10353
ImGui::Separator();
10354
10355
// About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
10356
// They have multiple effects:
10357
// - Display a dot next to the title.
10358
// - Tab is selected when clicking the X close button.
10359
// - Closure is not assumed (will wait for user to stop submitting the tab).
10360
// Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
10361
// We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
10362
// hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
10363
// The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
10364
10365
// Submit Tab Bar and Tabs
10366
{
10367
ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
10368
tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
10369
if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
10370
{
10371
if (opt_reorderable)
10372
app.NotifyOfDocumentsClosedElsewhere();
10373
10374
// [DEBUG] Stress tests
10375
//if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
10376
//if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
10377
10378
// Submit Tabs
10379
for (MyDocument& doc : app.Documents)
10380
{
10381
if (!doc.Open)
10382
continue;
10383
10384
// As we allow to change document name, we append a never-changing document id so tabs are stable
10385
char doc_name_buf[64];
10386
app.GetTabName(&doc, doc_name_buf, sizeof(doc_name_buf));
10387
ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
10388
bool visible = ImGui::BeginTabItem(doc_name_buf, &doc.Open, tab_flags);
10389
10390
// Cancel attempt to close when unsaved add to save queue so we can display a popup.
10391
if (!doc.Open && doc.Dirty)
10392
{
10393
doc.Open = true;
10394
app.CloseQueue.push_back(&doc);
10395
}
10396
10397
app.DisplayDocContextMenu(&doc);
10398
if (visible)
10399
{
10400
app.DisplayDocContents(&doc);
10401
ImGui::EndTabItem();
10402
}
10403
}
10404
10405
ImGui::EndTabBar();
10406
}
10407
}
10408
10409
// Display renaming UI
10410
if (app.RenamingDoc != NULL)
10411
{
10412
if (app.RenamingStarted)
10413
ImGui::OpenPopup("Rename");
10414
if (ImGui::BeginPopup("Rename"))
10415
{
10416
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30);
10417
if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_COUNTOF(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue))
10418
{
10419
ImGui::CloseCurrentPopup();
10420
app.RenamingDoc = NULL;
10421
}
10422
if (app.RenamingStarted)
10423
ImGui::SetKeyboardFocusHere(-1);
10424
ImGui::EndPopup();
10425
}
10426
else
10427
{
10428
app.RenamingDoc = NULL;
10429
}
10430
app.RenamingStarted = false;
10431
}
10432
10433
// Display closing confirmation UI
10434
if (!app.CloseQueue.empty())
10435
{
10436
int close_queue_unsaved_documents = 0;
10437
for (int n = 0; n < app.CloseQueue.Size; n++)
10438
if (app.CloseQueue[n]->Dirty)
10439
close_queue_unsaved_documents++;
10440
10441
if (close_queue_unsaved_documents == 0)
10442
{
10443
// Close documents when all are unsaved
10444
for (int n = 0; n < app.CloseQueue.Size; n++)
10445
app.CloseQueue[n]->DoForceClose();
10446
app.CloseQueue.clear();
10447
}
10448
else
10449
{
10450
if (!ImGui::IsPopupOpen("Save?"))
10451
ImGui::OpenPopup("Save?");
10452
if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
10453
{
10454
ImGui::Text("Save change to the following items?");
10455
float item_height = ImGui::GetTextLineHeightWithSpacing();
10456
if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
10457
for (MyDocument* doc : app.CloseQueue)
10458
if (doc->Dirty)
10459
ImGui::Text("%s", doc->Name);
10460
ImGui::EndChild();
10461
10462
ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
10463
if (ImGui::Button("Yes", button_size))
10464
{
10465
for (MyDocument* doc : app.CloseQueue)
10466
{
10467
if (doc->Dirty)
10468
doc->DoSave();
10469
doc->DoForceClose();
10470
}
10471
app.CloseQueue.clear();
10472
ImGui::CloseCurrentPopup();
10473
}
10474
ImGui::SameLine();
10475
if (ImGui::Button("No", button_size))
10476
{
10477
for (MyDocument* doc : app.CloseQueue)
10478
doc->DoForceClose();
10479
app.CloseQueue.clear();
10480
ImGui::CloseCurrentPopup();
10481
}
10482
ImGui::SameLine();
10483
if (ImGui::Button("Cancel", button_size))
10484
{
10485
app.CloseQueue.clear();
10486
ImGui::CloseCurrentPopup();
10487
}
10488
ImGui::EndPopup();
10489
}
10490
}
10491
}
10492
10493
ImGui::End();
10494
}
10495
10496
//-----------------------------------------------------------------------------
10497
// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
10498
//-----------------------------------------------------------------------------
10499
10500
//#include "imgui_internal.h" // NavMoveRequestTryWrapping()
10501
10502
struct ExampleAsset
10503
{
10504
ImGuiID ID;
10505
int Type;
10506
10507
ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; }
10508
10509
static const ImGuiTableSortSpecs* s_current_sort_specs;
10510
10511
static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count)
10512
{
10513
s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
10514
if (items_count > 1)
10515
qsort(items, (size_t)items_count, sizeof(items[0]), ExampleAsset::CompareWithSortSpecs);
10516
s_current_sort_specs = NULL;
10517
}
10518
10519
// Compare function to be used by qsort()
10520
static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
10521
{
10522
const ExampleAsset* a = (const ExampleAsset*)lhs;
10523
const ExampleAsset* b = (const ExampleAsset*)rhs;
10524
for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
10525
{
10526
const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
10527
int delta = 0;
10528
if (sort_spec->ColumnIndex == 0)
10529
delta = ((int)a->ID - (int)b->ID);
10530
else if (sort_spec->ColumnIndex == 1)
10531
delta = (a->Type - b->Type);
10532
if (delta > 0)
10533
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
10534
if (delta < 0)
10535
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
10536
}
10537
return (int)a->ID - (int)b->ID;
10538
}
10539
};
10540
const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;
10541
10542
struct ExampleAssetsBrowser
10543
{
10544
// Options
10545
bool ShowTypeOverlay = true;
10546
bool AllowSorting = true;
10547
bool AllowDragUnselected = false;
10548
bool AllowBoxSelect = true;
10549
float IconSize = 32.0f;
10550
int IconSpacing = 10;
10551
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.
10552
bool StretchSpacing = true;
10553
10554
// State
10555
ImVector<ExampleAsset> Items; // Our items
10556
ExampleSelectionWithDeletion Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
10557
ImGuiID NextItemId = 0; // Unique identifier when creating new items
10558
bool RequestDelete = false; // Deferred deletion request
10559
bool RequestSort = false; // Deferred sort request
10560
float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better
10561
10562
// Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way.
10563
ImVec2 LayoutItemSize;
10564
ImVec2 LayoutItemStep; // == LayoutItemSize + LayoutItemSpacing
10565
float LayoutItemSpacing = 0.0f;
10566
float LayoutSelectableSpacing = 0.0f;
10567
float LayoutOuterPadding = 0.0f;
10568
int LayoutColumnCount = 0;
10569
int LayoutLineCount = 0;
10570
10571
// Functions
10572
ExampleAssetsBrowser()
10573
{
10574
AddItems(10000);
10575
}
10576
void AddItems(int count)
10577
{
10578
if (Items.Size == 0)
10579
NextItemId = 0;
10580
Items.reserve(Items.Size + count);
10581
for (int n = 0; n < count; n++, NextItemId++)
10582
Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
10583
RequestSort = true;
10584
}
10585
void ClearItems()
10586
{
10587
Items.clear();
10588
Selection.Clear();
10589
}
10590
10591
// Logic would be written in the main code BeginChild() and outputting to local variables.
10592
// We extracted it into a function so we can call it easily from multiple places.
10593
void UpdateLayoutSizes(float avail_width)
10594
{
10595
// Layout: when not stretching: allow extending into right-most spacing.
10596
LayoutItemSpacing = (float)IconSpacing;
10597
if (StretchSpacing == false)
10598
avail_width += floorf(LayoutItemSpacing * 0.5f);
10599
10600
// Layout: calculate number of icon per line and number of lines
10601
LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
10602
LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
10603
LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount;
10604
10605
// Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
10606
if (StretchSpacing && LayoutColumnCount > 1)
10607
LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount;
10608
10609
LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing);
10610
LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f);
10611
LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
10612
}
10613
10614
void Draw(const char* title, bool* p_open)
10615
{
10616
ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
10617
if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
10618
{
10619
ImGui::End();
10620
return;
10621
}
10622
10623
// Menu bar
10624
if (ImGui::BeginMenuBar())
10625
{
10626
if (ImGui::BeginMenu("File"))
10627
{
10628
if (ImGui::MenuItem("Add 10000 items"))
10629
AddItems(10000);
10630
if (ImGui::MenuItem("Clear items"))
10631
ClearItems();
10632
ImGui::Separator();
10633
if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
10634
*p_open = false;
10635
ImGui::EndMenu();
10636
}
10637
if (ImGui::BeginMenu("Edit"))
10638
{
10639
if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10640
RequestDelete = true;
10641
ImGui::EndMenu();
10642
}
10643
if (ImGui::BeginMenu("Options"))
10644
{
10645
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
10646
10647
ImGui::SeparatorText("Contents");
10648
ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay);
10649
ImGui::Checkbox("Allow Sorting", &AllowSorting);
10650
10651
ImGui::SeparatorText("Selection Behavior");
10652
ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected);
10653
ImGui::Checkbox("Allow box-selection", &AllowBoxSelect);
10654
10655
ImGui::SeparatorText("Layout");
10656
ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f");
10657
ImGui::SameLine(); HelpMarker("Use Ctrl+Wheel to zoom");
10658
ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
10659
ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
10660
ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
10661
ImGui::PopItemWidth();
10662
ImGui::EndMenu();
10663
}
10664
ImGui::EndMenuBar();
10665
}
10666
10667
// Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
10668
if (AllowSorting)
10669
{
10670
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
10671
ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
10672
if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight())))
10673
{
10674
ImGui::TableSetupColumn("Index");
10675
ImGui::TableSetupColumn("Type");
10676
ImGui::TableHeadersRow();
10677
if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
10678
if (sort_specs->SpecsDirty || RequestSort)
10679
{
10680
ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
10681
sort_specs->SpecsDirty = RequestSort = false;
10682
}
10683
ImGui::EndTable();
10684
}
10685
ImGui::PopStyleVar();
10686
}
10687
10688
ImGuiIO& io = ImGui::GetIO();
10689
ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing)));
10690
if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove))
10691
{
10692
ImDrawList* draw_list = ImGui::GetWindowDrawList();
10693
10694
const float avail_width = ImGui::GetContentRegionAvail().x;
10695
UpdateLayoutSizes(avail_width);
10696
10697
// Calculate and store start position.
10698
ImVec2 start_pos = ImGui::GetCursorScreenPos();
10699
start_pos = ImVec2(start_pos.x + LayoutOuterPadding, start_pos.y + LayoutOuterPadding);
10700
ImGui::SetCursorScreenPos(start_pos);
10701
10702
// Multi-select
10703
ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid;
10704
10705
// - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items)
10706
if (AllowBoxSelect)
10707
ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d;
10708
10709
// - This feature allows dragging an unselected item without selecting it (rarely used)
10710
if (AllowDragUnselected)
10711
ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease;
10712
10713
// - Enable keyboard wrapping on X axis
10714
// (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing:
10715
// ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
10716
// When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system)
10717
ms_flags |= ImGuiMultiSelectFlags_NavWrapX;
10718
10719
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
10720
10721
// Use custom selection adapter: store ID in selection (recommended)
10722
Selection.UserData = this;
10723
Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
10724
Selection.ApplyRequests(ms_io);
10725
10726
const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
10727
const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
10728
RequestDelete = false;
10729
10730
// Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items)
10731
// Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
10732
// But it is necessary for two reasons:
10733
// - Selectables uses it by default to visually fill the space between two items.
10734
// - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do).
10735
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing));
10736
10737
// Rendering parameters
10738
const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) };
10739
const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220));
10740
const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f);
10741
const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x);
10742
10743
const int column_count = LayoutColumnCount;
10744
ImGuiListClipper clipper;
10745
clipper.Begin(LayoutLineCount, LayoutItemStep.y);
10746
if (item_curr_idx_to_focus != -1)
10747
clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
10748
if (ms_io->RangeSrcItem != -1)
10749
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
10750
while (clipper.Step())
10751
{
10752
for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
10753
{
10754
const int item_min_idx_for_current_line = line_idx * column_count;
10755
const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size);
10756
for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx)
10757
{
10758
ExampleAsset* item_data = &Items[item_idx];
10759
ImGui::PushID((int)item_data->ID);
10760
10761
// Position item
10762
ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y);
10763
ImGui::SetCursorScreenPos(pos);
10764
10765
ImGui::SetNextItemSelectionUserData(item_idx);
10766
bool item_is_selected = Selection.Contains((ImGuiID)item_data->ID);
10767
bool item_is_visible = ImGui::IsRectVisible(LayoutItemSize);
10768
ImGui::Selectable("", item_is_selected, ImGuiSelectableFlags_None, LayoutItemSize);
10769
10770
// Update our selection state immediately (without waiting for EndMultiSelect() requests)
10771
// because we use this to alter the color of our text/icon.
10772
if (ImGui::IsItemToggledSelection())
10773
item_is_selected = !item_is_selected;
10774
10775
// Focus (for after deletion)
10776
if (item_curr_idx_to_focus == item_idx)
10777
ImGui::SetKeyboardFocusHere(-1);
10778
10779
// Drag and drop
10780
if (ImGui::BeginDragDropSource())
10781
{
10782
// Create payload with full selection OR single unselected item.
10783
// (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
10784
if (ImGui::GetDragDropPayload() == NULL)
10785
{
10786
ImVector<ImGuiID> payload_items;
10787
void* it = NULL;
10788
ImGuiID id = 0;
10789
if (!item_is_selected)
10790
payload_items.push_back(item_data->ID);
10791
else
10792
while (Selection.GetNextSelectedItem(&it, &id))
10793
payload_items.push_back(id);
10794
ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
10795
}
10796
10797
// Display payload content in tooltip, by extracting it from the payload data
10798
// (we could read from selection, but it is more correct and reusable to read from payload)
10799
const ImGuiPayload* payload = ImGui::GetDragDropPayload();
10800
const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID);
10801
ImGui::Text("%d assets", payload_count);
10802
10803
ImGui::EndDragDropSource();
10804
}
10805
10806
// Render icon (a real app would likely display an image/thumbnail here)
10807
// Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well.
10808
if (item_is_visible)
10809
{
10810
ImVec2 box_min(pos.x - 1, pos.y - 1);
10811
ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious
10812
draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color
10813
if (ShowTypeOverlay && item_data->Type != 0)
10814
{
10815
ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_COUNTOF(icon_type_overlay_colors)];
10816
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);
10817
}
10818
if (display_label)
10819
{
10820
ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled);
10821
char label[32];
10822
sprintf(label, "%d", item_data->ID);
10823
draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label);
10824
}
10825
}
10826
10827
ImGui::PopID();
10828
}
10829
}
10830
}
10831
clipper.End();
10832
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
10833
10834
// Context menu
10835
if (ImGui::BeginPopupContextWindow())
10836
{
10837
ImGui::Text("Selection: %d items", Selection.Size);
10838
ImGui::Separator();
10839
if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10840
RequestDelete = true;
10841
ImGui::EndPopup();
10842
}
10843
10844
ms_io = ImGui::EndMultiSelect();
10845
Selection.ApplyRequests(ms_io);
10846
if (want_delete)
10847
Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
10848
10849
// Zooming with Ctrl+Wheel
10850
if (ImGui::IsWindowAppearing())
10851
ZoomWheelAccum = 0.0f;
10852
if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
10853
{
10854
ZoomWheelAccum += io.MouseWheel;
10855
if (fabsf(ZoomWheelAccum) >= 1.0f)
10856
{
10857
// Calculate hovered item index from mouse location
10858
// FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it.
10859
const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x;
10860
const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y;
10861
const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx;
10862
//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
10863
10864
// Zoom
10865
IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
10866
IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
10867
ZoomWheelAccum -= (int)ZoomWheelAccum;
10868
UpdateLayoutSizes(avail_width);
10869
10870
// Manipulate scroll to that we will land at the same Y location of currently hovered item.
10871
// - Calculate next frame position of item under mouse
10872
// - Set new scroll position to be used in next ImGui::BeginChild() call.
10873
float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y;
10874
hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y;
10875
float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y;
10876
ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y);
10877
}
10878
}
10879
}
10880
ImGui::EndChild();
10881
10882
ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
10883
ImGui::End();
10884
}
10885
};
10886
10887
void ShowExampleAppAssetsBrowser(bool* p_open)
10888
{
10889
IMGUI_DEMO_MARKER("Examples/Assets Browser");
10890
static ExampleAssetsBrowser assets_browser;
10891
assets_browser.Draw("Example: Assets Browser", p_open);
10892
}
10893
10894
// End of Demo code
10895
#else
10896
10897
void ImGui::ShowAboutWindow(bool*) {}
10898
void ImGui::ShowDemoWindow(bool*) {}
10899
void ImGui::ShowUserGuide() {}
10900
void ImGui::ShowStyleEditor(ImGuiStyle*) {}
10901
bool ImGui::ShowStyleSelector(const char*) { return false; }
10902
10903
#endif // #ifndef IMGUI_DISABLE_DEMO_WINDOWS
10904
10905
#endif // #ifndef IMGUI_DISABLE
10906
10907