openMSX
imgui_demo.cc
Go to the documentation of this file.
1// dear imgui, v1.91.6
2// (demo code)
3
4// Help:
5// - Read FAQ at http://dearimgui.com/faq
6// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7// - Need help integrating Dear ImGui in your codebase?
8// - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started
9// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
10// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
11// Get the latest version at https://github.com/ocornut/imgui
12
13// How to easily locate code?
14// - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools
15// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html
16// - Find a visible string and search for it in the code!
17
18//---------------------------------------------------
19// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT!
20//---------------------------------------------------
21// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase:
22// Think again! It is the most useful reference code that you and other coders will want to refer to and call.
23// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app!
24// Also include Metrics! ItemPicker! DebugLog! and other debug features.
25// Removing this file from your project is hindering access to documentation for everyone in your team,
26// likely leading you to poorer usage of the library.
27// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
28// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
29// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
30// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference.
31// Thank you,
32// -Your beloved friend, imgui_demo.cpp (which you won't delete)
33
34//--------------------------------------------
35// ABOUT THE MEANING OF THE 'static' KEYWORD:
36//--------------------------------------------
37// In this demo code, we frequently use 'static' variables inside functions.
38// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function.
39// Think of "static int n = 0;" as "global int n = 0;" !
40// We do this IN THE DEMO because we want:
41// - to gather code and data in the same place.
42// - to make the demo source code faster to read, faster to change, smaller in size.
43// - it is also a convenient way of storing simple UI related information as long as your function
44// doesn't need to be reentrant or used in multiple threads.
45// This might be a pattern you will want to use in your code, but most of the data you would be working
46// with in a complex codebase is likely going to be stored outside your functions.
47
48//-----------------------------------------
49// ABOUT THE CODING STYLE OF OUR DEMO CODE
50//-----------------------------------------
51// The Demo code in this file is designed to be easy to copy-and-paste into your application!
52// Because of this:
53// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
54// - We try to declare static variables in the local scope, as close as possible to the code using them.
55// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
56// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
57// by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional
58// and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
59// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
60
61// Navigating this file:
62// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
63// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
64// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
65// - You can search/grep for all sections listed in the index to find the section.
66
67/*
68
69Index of this file:
70
71// [SECTION] Forward Declarations
72// [SECTION] Helpers
73// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
74// [SECTION] Demo Window / ShowDemoWindow()
75// [SECTION] ShowDemoWindowMenuBar()
76// [SECTION] ShowDemoWindowWidgets()
77// [SECTION] ShowDemoWindowMultiSelect()
78// [SECTION] ShowDemoWindowLayout()
79// [SECTION] ShowDemoWindowPopups()
80// [SECTION] ShowDemoWindowTables()
81// [SECTION] ShowDemoWindowInputs()
82// [SECTION] About Window / ShowAboutWindow()
83// [SECTION] Style Editor / ShowStyleEditor()
84// [SECTION] User Guide / ShowUserGuide()
85// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
86// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
87// [SECTION] Example App: Debug Log / ShowExampleAppLog()
88// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
89// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
90// [SECTION] Example App: Long Text / ShowExampleAppLongText()
91// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
92// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
93// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
94// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
95// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
96// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
97// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
98// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
99// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
100
101*/
102
103#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
104#define _CRT_SECURE_NO_WARNINGS
105#endif
106
107#include "imgui.h"
108#ifndef IMGUI_DISABLE
109
110// System includes
111#include <ctype.h> // toupper
112#include <limits.h> // INT_MIN, INT_MAX
113#include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
114#include <stdio.h> // vsnprintf, sscanf, printf
115#include <stdlib.h> // NULL, malloc, free, atoi
116#include <stdint.h> // intptr_t
117#if !defined(_MSC_VER) || _MSC_VER >= 1800
118#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
119#endif
120#ifdef __EMSCRIPTEN__
121#include <emscripten/version.h> // __EMSCRIPTEN_major__ etc.
122#endif
123
124// Visual Studio warnings
125#ifdef _MSC_VER
126#pragma warning (disable: 4127) // condition expression is constant
127#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
128#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
129#endif
130
131// Clang/GCC warnings with -Weverything
132#if defined(__clang__)
133#if __has_warning("-Wunknown-warning-option")
134#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
135#endif
136#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
137#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
138#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code)
139#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type
140#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal
141#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
142#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used.
143#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
144#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
145#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
146#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
147#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
148#elif defined(__GNUC__)
149#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
150#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
151#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure)
152#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
153#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
154#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub.
155#endif
156
157// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
158#ifdef _WIN32
159#define IM_NEWLINE "\r\n"
160#else
161#define IM_NEWLINE "\n"
162#endif
163
164// Helpers
165#if defined(_MSC_VER) && !defined(snprintf)
166#define snprintf _snprintf
167#endif
168#if defined(_MSC_VER) && !defined(vsnprintf)
169#define vsnprintf _vsnprintf
170#endif
171
172// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
173#if !defined(PRId64) && defined(_MSC_VER)
174#define PRId64 "I64d"
175#define PRIu64 "I64u"
176#elif !defined(PRId64)
177#define PRId64 "lld"
178#define PRIu64 "llu"
179#endif
180
181// Helpers macros
182// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
183// but making an exception here as those are largely simplifying code...
184// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
185#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B))
186#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B))
187#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
188
189// Enforce cdecl calling convention for functions called by the standard library,
190// in case compilation settings changed the default to e.g. __vectorcall
191#ifndef IMGUI_CDECL
192#ifdef _MSC_VER
193#define IMGUI_CDECL __cdecl
194#else
195#define IMGUI_CDECL
196#endif
197#endif
198
199//-----------------------------------------------------------------------------
200// [SECTION] Forward Declarations
201//-----------------------------------------------------------------------------
202
203#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
204
205// Forward Declarations
207static void ShowExampleAppMainMenuBar();
208static void ShowExampleAppAssetsBrowser(bool* p_open);
209static void ShowExampleAppConsole(bool* p_open);
210static void ShowExampleAppCustomRendering(bool* p_open);
211static void ShowExampleAppDockSpace(bool* p_open);
212static void ShowExampleAppDocuments(bool* p_open);
213static void ShowExampleAppLog(bool* p_open);
214static void ShowExampleAppLayout(bool* p_open);
215static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data);
216static void ShowExampleAppSimpleOverlay(bool* p_open);
217static void ShowExampleAppAutoResize(bool* p_open);
218static void ShowExampleAppConstrainedResize(bool* p_open);
219static void ShowExampleAppFullscreen(bool* p_open);
220static void ShowExampleAppLongText(bool* p_open);
221static void ShowExampleAppWindowTitles(bool* p_open);
222static void ShowExampleMenuFile();
223
224// We split the contents of the big ShowDemoWindow() function into smaller functions
225// (because the link time of very large functions tends to grow non-linearly)
226static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data);
227static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data);
228static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data);
229static void ShowDemoWindowLayout();
230static void ShowDemoWindowPopups();
231static void ShowDemoWindowTables();
232static void ShowDemoWindowColumns();
233static void ShowDemoWindowInputs();
234
235//-----------------------------------------------------------------------------
236// [SECTION] Helpers
237//-----------------------------------------------------------------------------
238
239// Helper to display a little (?) mark which shows a tooltip when hovered.
240// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
241static void HelpMarker(const char* desc)
242{
243 ImGui::TextDisabled("(?)");
244 if (ImGui::BeginItemTooltip())
245 {
246 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
248 ImGui::PopTextWrapPos();
249 ImGui::EndTooltip();
250 }
251}
252
253static void ShowDockingDisabledMessage()
254{
255 ImGuiIO& io = ImGui::GetIO();
256 ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
257 ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
258 ImGui::SameLine(0.0f, 0.0f);
259 if (ImGui::SmallButton("click here"))
260 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
261}
262
263// Helper to wire demo markers located in code to an interactive browser
264typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
269#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
270
271//-----------------------------------------------------------------------------
272// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.)
273//-----------------------------------------------------------------------------
274
275// Simple representation for a tree
276// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.)
278{
279 // Tree structure
280 char Name[28] = "";
281 int UID = 0;
283 ImVector<ExampleTreeNode*> Childs;
284 unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily
285
286 // Leaf Data
287 bool HasData = false; // All leaves have data
288 bool DataMyBool = true;
289 int DataMyInt = 128;
290 ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f);
291};
292
293// Simple representation of struct metadata/serialization data.
294// (this is a minimal version of what a typical advanced application may provide)
296{
297 const char* Name; // Member name
298 ImGuiDataType DataType; // Member type
299 int DataCount; // Member count (1 when scalar)
300 int Offset; // Offset inside parent structure
301};
302
303// Metadata description of ExampleTreeNode struct.
304static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]
305{
306 { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) },
307 { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) },
308 { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) },
309};
310
311static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent)
312{
313 ExampleTreeNode* node = IM_NEW(ExampleTreeNode);
314 snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name);
315 node->UID = uid;
316 node->Parent = parent;
317 node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0;
318 if (parent)
319 parent->Childs.push_back(node);
320 return node;
321}
322
323static void ExampleTree_DestroyNode(ExampleTreeNode* node)
324{
325 for (ExampleTreeNode* child_node : node->Childs)
326 ExampleTree_DestroyNode(child_node);
327 IM_DELETE(node);
328}
329
330// Create example tree data
331// (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
332static ExampleTreeNode* ExampleTree_CreateDemoTree()
333{
334 static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
335 const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
336 char name_buf[NAME_MAX_LEN];
337 int uid = 0;
338 ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
339 const int root_items_multiplier = 2;
340 for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++)
341 {
342 snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier);
343 ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
344 const int number_of_childs = (int)strlen(node_L1->Name);
345 for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
346 {
347 snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1);
348 ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1);
349 node_L2->HasData = true;
350 if (idx_L1 == 0)
351 {
352 snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0);
353 ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2);
354 node_L3->HasData = true;
355 }
356 }
357 }
358 return node_L0;
359}
360
361//-----------------------------------------------------------------------------
362// [SECTION] Demo Window / ShowDemoWindow()
363//-----------------------------------------------------------------------------
364
365// Data to be shared across different functions of the demo.
367{
368 // Examples Apps (accessible from the "Examples" menu)
369 bool ShowMainMenuBar = false;
371 bool ShowAppConsole = false;
373 bool ShowAppDocuments = false;
374 bool ShowAppDockSpace = false;
375 bool ShowAppLog = false;
376 bool ShowAppLayout = false;
379 bool ShowAppAutoResize = false;
381 bool ShowAppFullscreen = false;
382 bool ShowAppLongText = false;
384
385 // Dear ImGui Tools (accessible from the "Tools" menu)
386 bool ShowMetrics = false;
387 bool ShowDebugLog = false;
388 bool ShowIDStackTool = false;
389 bool ShowStyleEditor = false;
390 bool ShowAbout = false;
391
392 // Other data
394
395 ~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); }
396};
397
398// Demonstrate most Dear ImGui features (this is big function!)
399// You may execute this function to experiment with the UI and understand what it does.
400// You may then search for keywords in the code when you are interested by a specific feature.
401void ImGui::ShowDemoWindow(bool* p_open)
402{
403 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
404 // Most functions would normally just assert/crash if the context is missing.
405 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
406
407 // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
408 IMGUI_CHECKVERSION();
409
410 // Stored data
411 static ImGuiDemoWindowData demo_data;
412
413 // Examples Apps (accessible from the "Examples" menu)
414 if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); }
415 if (demo_data.ShowAppDockSpace) { ShowExampleAppDockSpace(&demo_data.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
416 if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace()
417 if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
418 if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
419 if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
420 if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); }
421 if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
422 if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
423 if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); }
424 if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); }
425 if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); }
426 if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); }
427 if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); }
428 if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); }
429
430 // Dear ImGui Tools (accessible from the "Tools" menu)
431 if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); }
432 if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); }
433 if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); }
434 if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); }
435 if (demo_data.ShowStyleEditor)
436 {
437 ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor);
438 ImGui::ShowStyleEditor();
439 ImGui::End();
440 }
441
442 // Demonstrate the various window flags. Typically you would just use the default!
443 static bool no_titlebar = false;
444 static bool no_scrollbar = false;
445 static bool no_menu = false;
446 static bool no_move = false;
447 static bool no_resize = false;
448 static bool no_collapse = false;
449 static bool no_close = false;
450 static bool no_nav = false;
451 static bool no_background = false;
452 static bool no_bring_to_front = false;
453 static bool no_docking = false;
454 static bool unsaved_document = false;
455
456 ImGuiWindowFlags window_flags = 0;
457 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
458 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
459 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
460 if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
461 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
462 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
463 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
464 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
465 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
466 if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
467 if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
468 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
469
470 // We specify a default position/size in case there's no data in the .ini file.
471 // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
472 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
473 ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
474 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
475
476 // Main body of the Demo window starts here.
477 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
478 {
479 // Early out if the window is collapsed, as an optimization.
480 ImGui::End();
481 return;
482 }
483
484 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
485 ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
486 //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
487
488 // Menu Bar
489 ShowDemoWindowMenuBar(&demo_data);
490
491 ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
492 ImGui::Spacing();
493
494 IMGUI_DEMO_MARKER("Help");
495 if (ImGui::CollapsingHeader("Help"))
496 {
497 ImGui::SeparatorText("ABOUT THIS DEMO:");
498 ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
499 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
500 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
501 "and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
502
503 ImGui::SeparatorText("PROGRAMMER GUIDE:");
504 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
505 ImGui::BulletText("See comments in imgui.cpp.");
506 ImGui::BulletText("See example applications in the examples/ folder.");
507 ImGui::BulletText("Read the FAQ at ");
508 ImGui::SameLine(0, 0);
509 ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/");
510 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
511 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
512
513 ImGui::SeparatorText("USER GUIDE:");
514 ImGui::ShowUserGuide();
515 }
516
517 IMGUI_DEMO_MARKER("Configuration");
518 if (ImGui::CollapsingHeader("Configuration"))
519 {
520 ImGuiIO& io = ImGui::GetIO();
521
522 if (ImGui::TreeNode("Configuration##2"))
523 {
524 ImGui::SeparatorText("General");
525 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
526 ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
527 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
528 ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
529 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
530 ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
531
532 // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
533 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
534 {
535 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
536 {
537 ImGui::SameLine();
538 ImGui::Text("<<PRESS SPACE TO DISABLE>>");
539 }
540 // Prevent both being checked
541 if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
542 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
543 }
544
545 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
546 ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
547 ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
548 ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
549
550 ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
551 ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
552 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
553 ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
554
555 ImGui::SeparatorText("Keyboard/Gamepad Navigation");
556 ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons);
557 ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos);
558 ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult");
559 ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard);
560 ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem);
561 ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item.");
562 ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow);
563 ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window.");
564 ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto);
565 ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor.");
566 ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways);
567 ImGui::SameLine(); HelpMarker("Navigation cursor is always visible.");
568
569 ImGui::SeparatorText("Docking");
570 ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
571 ImGui::SameLine();
572 if (io.ConfigDockingWithShift)
573 HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
574 else
575 HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
576 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
577 {
578 ImGui::Indent();
579 ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
580 ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
581 ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
582 ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
583 ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
584 ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
585 ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
586 ImGui::SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.");
587 ImGui::Unindent();
588 }
589
590 ImGui::SeparatorText("Multi-viewports");
591 ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
592 ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
593 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
594 {
595 ImGui::Indent();
596 ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
597 ImGui::SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.");
598 ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
599 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
600 ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
601 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
602 ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
603 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
604 ImGui::Unindent();
605 }
606
607 ImGui::SeparatorText("Windows");
608 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
609 ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback.");
610 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
611 ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL]
612 ImGui::SameLine(); HelpMarker("*EXPERIMENTAL* CTRL+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order.");
613 ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage);
614 ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.");
615
616 ImGui::SeparatorText("Widgets");
617 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
618 ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
619 ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
620 ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only).");
621 ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
622 ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
623 ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
624 ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
625 ImGui::Text("Also see Style->Rendering for rendering options.");
626
627 // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
628 ImGui::SeparatorText("Error Handling");
629
630 ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery);
631 ImGui::SameLine(); HelpMarker(
632 "Options to configure how we handle recoverable errors.\n"
633 "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n"
634 "- You not are not supposed to rely on it in the course of a normal application run.\n"
635 "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n"
636 "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call!"
637 "Otherwise it would severely hinder your ability to catch and correct mistakes!");
638 ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert);
639 ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog);
640 ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip);
641 if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip)
642 io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true;
643
644 // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools
645 ImGui::SeparatorText("Debug");
646 ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
647 ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.");
648 ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
649 ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
650 ImGui::BeginDisabled();
651 ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
652 ImGui::EndDisabled();
653 ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.");
654 ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
655 ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.");
656 ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
657 ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
658 ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
659 ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
660
661 ImGui::TreePop();
662 ImGui::Spacing();
663 }
664
665 IMGUI_DEMO_MARKER("Configuration/Backend Flags");
666 if (ImGui::TreeNode("Backend Flags"))
667 {
668 HelpMarker(
669 "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
670 "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
671
672 // Make a local copy to avoid modifying actual backend flags.
673 // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
674 ImGui::BeginDisabled();
675 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
676 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
677 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
678 ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
679 ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
680 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
681 ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
682 ImGui::EndDisabled();
683
684 ImGui::TreePop();
685 ImGui::Spacing();
686 }
687
688 IMGUI_DEMO_MARKER("Configuration/Style");
689 if (ImGui::TreeNode("Style"))
690 {
691 ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor);
692 ImGui::SameLine();
693 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
694 ImGui::TreePop();
695 ImGui::Spacing();
696 }
697
698 IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
699 if (ImGui::TreeNode("Capture/Logging"))
700 {
701 HelpMarker(
702 "The logging API redirects all text output so you can easily capture the content of "
703 "a window or a block. Tree nodes can be automatically expanded.\n"
704 "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
705 ImGui::LogButtons();
706
707 HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
708 if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
709 {
710 ImGui::LogToClipboard();
711 ImGui::LogText("Hello, world!");
712 ImGui::LogFinish();
713 }
714 ImGui::TreePop();
715 }
716 }
717
718 IMGUI_DEMO_MARKER("Window options");
719 if (ImGui::CollapsingHeader("Window options"))
720 {
721 if (ImGui::BeginTable("split", 3))
722 {
723 ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
724 ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
725 ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
726 ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
727 ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
728 ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
729 ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
730 ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
731 ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
732 ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
733 ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
734 ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
735 ImGui::EndTable();
736 }
737 }
738
739 // All demo contents
740 ShowDemoWindowWidgets(&demo_data);
741 ShowDemoWindowLayout();
742 ShowDemoWindowPopups();
743 ShowDemoWindowTables();
744 ShowDemoWindowInputs();
745
746 // End of ShowDemoWindow()
747 ImGui::PopItemWidth();
748 ImGui::End();
749}
750
751//-----------------------------------------------------------------------------
752// [SECTION] ShowDemoWindowMenuBar()
753//-----------------------------------------------------------------------------
754
755static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
756{
757 IMGUI_DEMO_MARKER("Menu");
758 if (ImGui::BeginMenuBar())
759 {
760 if (ImGui::BeginMenu("Menu"))
761 {
762 IMGUI_DEMO_MARKER("Menu/File");
763 ShowExampleMenuFile();
764 ImGui::EndMenu();
765 }
766 if (ImGui::BeginMenu("Examples"))
767 {
768 IMGUI_DEMO_MARKER("Menu/Examples");
769 ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar);
770
771 ImGui::SeparatorText("Mini apps");
772 ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser);
773 ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
774 ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
775 ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
776 ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace);
777 ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
778 ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
779 ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
780 ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay);
781
782 ImGui::SeparatorText("Concepts");
783 ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize);
784 ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize);
785 ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen);
786 ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText);
787 ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles);
788
789 ImGui::EndMenu();
790 }
791 //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
792 if (ImGui::BeginMenu("Tools"))
793 {
794 IMGUI_DEMO_MARKER("Menu/Tools");
795 ImGuiIO& io = ImGui::GetIO();
796#ifndef IMGUI_DISABLE_DEBUG_TOOLS
797 const bool has_debug_tools = true;
798#else
799 const bool has_debug_tools = false;
800#endif
801 ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
802 ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
803 ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
804 bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
805 if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
806 ImGui::DebugStartItemPicker();
807 if (!is_debugger_present)
808 ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools.");
809 ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
810 ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
811
812 ImGui::SeparatorText("Debug Options");
813 ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools);
814 ImGui::EndMenu();
815 }
816 ImGui::EndMenuBar();
817 }
818}
819
820//-----------------------------------------------------------------------------
821// [SECTION] ShowDemoWindowWidgets()
822//-----------------------------------------------------------------------------
823
824static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
825{
826 IMGUI_DEMO_MARKER("Widgets");
827 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
828 if (!ImGui::CollapsingHeader("Widgets"))
829 return;
830
831 static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom
832 if (disable_all)
833 ImGui::BeginDisabled();
834
835 IMGUI_DEMO_MARKER("Widgets/Basic");
836 if (ImGui::TreeNode("Basic"))
837 {
838 ImGui::SeparatorText("General");
839
840 IMGUI_DEMO_MARKER("Widgets/Basic/Button");
841 static int clicked = 0;
842 if (ImGui::Button("Button"))
843 clicked++;
844 if (clicked & 1)
845 {
846 ImGui::SameLine();
847 ImGui::Text("Thanks for clicking me!");
848 }
849
850 IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
851 static bool check = true;
852 ImGui::Checkbox("checkbox", &check);
853
854 IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
855 static int e = 0;
856 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
857 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
858 ImGui::RadioButton("radio c", &e, 2);
859
860 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
861 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
862 for (int i = 0; i < 7; i++)
863 {
864 if (i > 0)
865 ImGui::SameLine();
866 ImGui::PushID(i);
867 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
868 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
869 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
870 ImGui::Button("Click");
871 ImGui::PopStyleColor(3);
872 ImGui::PopID();
873 }
874
875 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
876 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
877 // See 'Demo->Layout->Text Baseline Alignment' for details.
878 ImGui::AlignTextToFramePadding();
879 ImGui::Text("Hold to repeat:");
880 ImGui::SameLine();
881
882 // Arrow buttons with Repeater
883 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
884 static int counter = 0;
885 float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
886 ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
887 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
888 ImGui::SameLine(0.0f, spacing);
889 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
890 ImGui::PopItemFlag();
891 ImGui::SameLine();
892 ImGui::Text("%d", counter);
893
894 ImGui::Button("Tooltip");
895 ImGui::SetItemTooltip("I am a tooltip");
896
897 ImGui::LabelText("label", "Value");
898
899 ImGui::SeparatorText("Inputs");
900
901 {
902 // To wire InputText() with std::string or any other custom string type,
903 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
904 IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
905 static char str0[128] = "Hello, world!";
906 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
907 ImGui::SameLine(); HelpMarker(
908 "USER:\n"
909 "Hold SHIFT or use mouse to select text.\n"
910 "CTRL+Left/Right to word jump.\n"
911 "CTRL+A or Double-Click to select all.\n"
912 "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
913 "CTRL+Z,CTRL+Y undo/redo.\n"
914 "ESCAPE to revert.\n\n"
915 "PROGRAMMER:\n"
916 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
917 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
918 "in imgui_demo.cpp).");
919
920 static char str1[128] = "";
921 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
922
923 IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
924 static int i0 = 123;
925 ImGui::InputInt("input int", &i0);
926
927 static float f0 = 0.001f;
928 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
929
930 static double d0 = 999999.00000001;
931 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
932
933 static float f1 = 1.e10f;
934 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
935 ImGui::SameLine(); HelpMarker(
936 "You can input value using the scientific notation,\n"
937 " e.g. \"1e+8\" becomes \"100000000\".");
938
939 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
940 ImGui::InputFloat3("input float3", vec4a);
941 }
942
943 ImGui::SeparatorText("Drags");
944
945 {
946 IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
947 static int i1 = 50, i2 = 42, i3 = 128;
948 ImGui::DragInt("drag int", &i1, 1);
949 ImGui::SameLine(); HelpMarker(
950 "Click and drag to edit value.\n"
951 "Hold SHIFT/ALT for faster/slower edit.\n"
952 "Double-click or CTRL+click to input value.");
953 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
954 ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
955
956 static float f1 = 1.00f, f2 = 0.0067f;
957 ImGui::DragFloat("drag float", &f1, 0.005f);
958 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
959 //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
960 }
961
962 ImGui::SeparatorText("Sliders");
963
964 {
965 IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
966 static int i1 = 0;
967 ImGui::SliderInt("slider int", &i1, -1, 3);
968 ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
969
970 static float f1 = 0.123f, f2 = 0.0f;
971 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
972 ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
973
974 IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
975 static float angle = 0.0f;
976 ImGui::SliderAngle("slider angle", &angle);
977
978 // Using the format string to display a name instead of an integer.
979 // Here we completely omit '%d' from the format string, so it'll only display a name.
980 // This technique can also be used with DragInt().
981 IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
982 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
983 static int elem = Element_Fire;
984 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
985 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
986 ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here.
987 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
988 }
989
990 ImGui::SeparatorText("Selectors/Pickers");
991
992 {
993 IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
994 static float col1[3] = { 1.0f, 0.0f, 0.2f };
995 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
996 ImGui::ColorEdit3("color 1", col1);
997 ImGui::SameLine(); HelpMarker(
998 "Click on the color square to open a color picker.\n"
999 "Click and hold to use drag and drop.\n"
1000 "Right-click on the color square to show options.\n"
1001 "CTRL+click on individual component to input value.\n");
1002
1003 ImGui::ColorEdit4("color 2", col2);
1004 }
1005
1006 {
1007 // Using the _simplified_ one-liner Combo() api here
1008 // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
1009 IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
1010 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
1011 static int item_current = 0;
1012 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
1013 ImGui::SameLine(); HelpMarker(
1014 "Using the simplified one-liner Combo API here.\n"
1015 "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
1016 }
1017
1018 {
1019 // Using the _simplified_ one-liner ListBox() api here
1020 // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
1021 IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
1022 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
1023 static int item_current = 1;
1024 ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4);
1025 ImGui::SameLine(); HelpMarker(
1026 "Using the simplified one-liner ListBox API here.\n"
1027 "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
1028 }
1029
1030 ImGui::TreePop();
1031 }
1032
1033 IMGUI_DEMO_MARKER("Widgets/Tooltips");
1034 if (ImGui::TreeNode("Tooltips"))
1035 {
1036 // Tooltips are windows following the mouse. They do not take focus away.
1037 ImGui::SeparatorText("General");
1038
1039 // Typical use cases:
1040 // - Short-form (text only): SetItemTooltip("Hello");
1041 // - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
1042
1043 // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); }
1044 // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
1045
1046 HelpMarker(
1047 "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
1048 "We provide a helper SetItemTooltip() function to perform the two with standards flags.");
1049
1050 ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
1051
1052 ImGui::Button("Basic", sz);
1053 ImGui::SetItemTooltip("I am a tooltip");
1054
1055 ImGui::Button("Fancy", sz);
1056 if (ImGui::BeginItemTooltip())
1057 {
1058 ImGui::Text("I am a fancy tooltip");
1059 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1060 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
1061 ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
1062 ImGui::EndTooltip();
1063 }
1064
1065 ImGui::SeparatorText("Always On");
1066
1067 // Showcase NOT relying on a IsItemHovered() to emit a tooltip.
1068 // Here the tooltip is always emitted when 'always_on == true'.
1069 static int always_on = 0;
1070 ImGui::RadioButton("Off", &always_on, 0);
1071 ImGui::SameLine();
1072 ImGui::RadioButton("Always On (Simple)", &always_on, 1);
1073 ImGui::SameLine();
1074 ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
1075 if (always_on == 1)
1076 ImGui::SetTooltip("I am following you around.");
1077 else if (always_on == 2 && ImGui::BeginTooltip())
1078 {
1079 ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
1080 ImGui::EndTooltip();
1081 }
1082
1083 ImGui::SeparatorText("Custom");
1084
1085 HelpMarker(
1086 "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize"
1087 "tooltip activation details across your application. You may however decide to use custom"
1088 "flags for a specific tooltip instance.");
1089
1090 // The following examples are passed for documentation purpose but may not be useful to most users.
1091 // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
1092 // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used.
1093 // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
1094 ImGui::Button("Manual", sz);
1095 if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1096 ImGui::SetTooltip("I am a manually emitted tooltip.");
1097
1098 ImGui::Button("DelayNone", sz);
1099 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
1100 ImGui::SetTooltip("I am a tooltip with no delay.");
1101
1102 ImGui::Button("DelayShort", sz);
1103 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
1104 ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
1105
1106 ImGui::Button("DelayLong", sz);
1107 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
1108 ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
1109
1110 ImGui::Button("Stationary", sz);
1111 if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
1112 ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
1113
1114 // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
1115 // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
1116 ImGui::BeginDisabled();
1117 ImGui::Button("Disabled item", sz);
1118 if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
1119 ImGui::SetTooltip("I am a a tooltip for a disabled item.");
1120 ImGui::EndDisabled();
1121
1122 ImGui::TreePop();
1123 }
1124
1125 // Testing ImGuiOnceUponAFrame helper.
1126 //static ImGuiOnceUponAFrame once;
1127 //for (int i = 0; i < 5; i++)
1128 // if (once)
1129 // ImGui::Text("This will be displayed only once.");
1130
1131 IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
1132 if (ImGui::TreeNode("Tree Nodes"))
1133 {
1134 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
1135 if (ImGui::TreeNode("Basic trees"))
1136 {
1137 for (int i = 0; i < 5; i++)
1138 {
1139 // Use SetNextItemOpen() so set the default state of a node to be open. We could
1140 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
1141 if (i == 0)
1142 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1143
1144 // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict.
1145 // An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)',
1146 // aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine.
1147 ImGui::PushID(i);
1148 if (ImGui::TreeNode("", "Child %d", i))
1149 {
1150 ImGui::Text("blah blah");
1151 ImGui::SameLine();
1152 if (ImGui::SmallButton("button")) {}
1153 ImGui::TreePop();
1154 }
1155 ImGui::PopID();
1156 }
1157 ImGui::TreePop();
1158 }
1159
1160 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
1161 if (ImGui::TreeNode("Advanced, with Selectable nodes"))
1162 {
1163 HelpMarker(
1164 "This is a more typical looking tree with selectable nodes.\n"
1165 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
1166 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
1167 static bool align_label_with_current_x_position = false;
1168 static bool test_drag_and_drop = false;
1169 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
1170 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
1171 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
1172 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
1173 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &base_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin.");
1174 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
1175 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
1176 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
1177 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere);
1178 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
1179 ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
1180 ImGui::Text("Hello!");
1181 if (align_label_with_current_x_position)
1182 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
1183
1184 // 'selection_mask' is dumb representation of what may be user-side selection state.
1185 // You may retain selection state inside or outside your objects in whatever format you see fit.
1186 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
1188 static int selection_mask = (1 << 2);
1189 int node_clicked = -1;
1190 for (int i = 0; i < 6; i++)
1191 {
1192 // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
1193 // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
1194 ImGuiTreeNodeFlags node_flags = base_flags;
1195 const bool is_selected = (selection_mask & (1 << i)) != 0;
1196 if (is_selected)
1197 node_flags |= ImGuiTreeNodeFlags_Selected;
1198 if (i < 3)
1199 {
1200 // Items 0..2 are Tree Node
1201 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
1202 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1203 node_clicked = i;
1204 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1205 {
1206 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1207 ImGui::Text("This is a drag and drop source");
1208 ImGui::EndDragDropSource();
1209 }
1210 if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth))
1211 {
1212 // Item 2 has an additional inline button to help demonstrate SpanTextWidth.
1213 ImGui::SameLine();
1214 if (ImGui::SmallButton("button")) {}
1215 }
1216 if (node_open)
1217 {
1218 ImGui::BulletText("Blah blah\nBlah Blah");
1219 ImGui::SameLine();
1220 ImGui::SmallButton("Button");
1221 ImGui::TreePop();
1222 }
1223 }
1224 else
1225 {
1226 // Items 3..5 are Tree Leaves
1227 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
1228 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
1229 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
1230 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
1231 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1232 node_clicked = i;
1233 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1234 {
1235 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1236 ImGui::Text("This is a drag and drop source");
1237 ImGui::EndDragDropSource();
1238 }
1239 }
1240 }
1241 if (node_clicked != -1)
1242 {
1243 // Update selection state
1244 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
1245 if (ImGui::GetIO().KeyCtrl)
1246 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
1247 else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
1248 selection_mask = (1 << node_clicked); // Click to single-select
1249 }
1250 if (align_label_with_current_x_position)
1251 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
1252 ImGui::TreePop();
1253 }
1254 ImGui::TreePop();
1255 }
1256
1257 IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1258 if (ImGui::TreeNode("Collapsing Headers"))
1259 {
1260 static bool closable_group = true;
1261 ImGui::Checkbox("Show 2nd header", &closable_group);
1262 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
1263 {
1264 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1265 for (int i = 0; i < 5; i++)
1266 ImGui::Text("Some content %d", i);
1267 }
1268 if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
1269 {
1270 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1271 for (int i = 0; i < 5; i++)
1272 ImGui::Text("More content %d", i);
1273 }
1274 /*
1275 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1276 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1277 */
1278 ImGui::TreePop();
1279 }
1280
1281 IMGUI_DEMO_MARKER("Widgets/Bullets");
1282 if (ImGui::TreeNode("Bullets"))
1283 {
1284 ImGui::BulletText("Bullet point 1");
1285 ImGui::BulletText("Bullet point 2\nOn multiple lines");
1286 if (ImGui::TreeNode("Tree node"))
1287 {
1288 ImGui::BulletText("Another bullet point");
1289 ImGui::TreePop();
1290 }
1291 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
1292 ImGui::Bullet(); ImGui::SmallButton("Button");
1293 ImGui::TreePop();
1294 }
1295
1296 IMGUI_DEMO_MARKER("Widgets/Text");
1297 if (ImGui::TreeNode("Text"))
1298 {
1299 IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
1300 if (ImGui::TreeNode("Colorful Text"))
1301 {
1302 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
1303 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
1304 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
1305 ImGui::TextDisabled("Disabled");
1306 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
1307 ImGui::TreePop();
1308 }
1309
1310 IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
1311 if (ImGui::TreeNode("Word Wrapping"))
1312 {
1313 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
1314 ImGui::TextWrapped(
1315 "This text should automatically wrap on the edge of the window. The current implementation "
1316 "for text wrapping follows simple rules suitable for English and possibly other languages.");
1317 ImGui::Spacing();
1318
1319 static float wrap_width = 200.0f;
1320 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
1321
1322 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1323 for (int n = 0; n < 2; n++)
1324 {
1325 ImGui::Text("Test paragraph %d:", n);
1326 ImVec2 pos = ImGui::GetCursorScreenPos();
1327 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
1328 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
1329 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
1330 if (n == 0)
1331 ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width);
1332 else
1333 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
1334
1335 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
1336 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
1337 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
1338 ImGui::PopTextWrapPos();
1339 }
1340
1341 ImGui::TreePop();
1342 }
1343
1344 IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
1345 if (ImGui::TreeNode("UTF-8 Text"))
1346 {
1347 // UTF-8 test with Japanese characters
1348 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
1349 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
1350 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
1351 // can save your source files as 'UTF-8 without signature').
1352 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
1353 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
1354 // Don't do this in your application! Please use u8"text in any language" in your application!
1355 // Note that characters values are preserved even by InputText() if the font cannot be displayed,
1356 // so you can safely copy & paste garbled characters into another application.
1357 ImGui::TextWrapped(
1358 "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
1359 "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
1360 "Read docs/FONTS.md for details.");
1361 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
1362 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
1363 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
1364 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
1365 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
1366 ImGui::TreePop();
1367 }
1368 ImGui::TreePop();
1369 }
1370
1371 IMGUI_DEMO_MARKER("Widgets/Images");
1372 if (ImGui::TreeNode("Images"))
1373 {
1374 ImGuiIO& io = ImGui::GetIO();
1375 ImGui::TextWrapped(
1376 "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1377 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1378 "Hover the texture for a zoomed view!");
1379
1380 // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1381 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
1382 // will be passed to the rendering backend via the ImDrawCmd structure.
1383 // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1384 // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
1385 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
1386 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1387 // More:
1388 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1389 // to ImGui::Image(), and gather width/height through your own functions, etc.
1390 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1391 // it will help you debug issues if you are confused about it.
1392 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1393 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1394 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1395 ImTextureID my_tex_id = io.Fonts->TexID;
1396 float my_tex_w = (float)io.Fonts->TexWidth;
1397 float my_tex_h = (float)io.Fonts->TexHeight;
1398 {
1399 static bool use_text_color_for_tint = false;
1400 ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
1401 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1402 ImVec2 pos = ImGui::GetCursorScreenPos();
1403 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1404 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1405 ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1406 ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
1407 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
1408 if (ImGui::BeginItemTooltip())
1409 {
1410 float region_sz = 32.0f;
1411 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1412 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1413 float zoom = 4.0f;
1414 if (region_x < 0.0f) { region_x = 0.0f; }
1415 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1416 if (region_y < 0.0f) { region_y = 0.0f; }
1417 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1418 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
1419 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1420 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1421 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1422 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
1423 ImGui::EndTooltip();
1424 }
1425 }
1426
1427 IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1428 ImGui::TextWrapped("And now some textured buttons..");
1429 static int pressed_count = 0;
1430 for (int i = 0; i < 8; i++)
1431 {
1432 // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1433 // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1434 // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1435 ImGui::PushID(i);
1436 if (i > 0)
1437 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
1438 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
1439 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
1440 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture
1441 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
1442 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1443 if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
1444 pressed_count += 1;
1445 if (i > 0)
1446 ImGui::PopStyleVar();
1447 ImGui::PopID();
1448 ImGui::SameLine();
1449 }
1450 ImGui::NewLine();
1451 ImGui::Text("Pressed %d times.", pressed_count);
1452 ImGui::TreePop();
1453 }
1454
1455 IMGUI_DEMO_MARKER("Widgets/Combo");
1456 if (ImGui::TreeNode("Combo"))
1457 {
1458 // Combo Boxes are also called "Dropdown" in other systems
1459 // Expose flags as checkbox for the demo
1460 static ImGuiComboFlags flags = 0;
1461 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1462 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1463 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1464 flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags
1465 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1466 flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1467 if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
1468 flags &= ~ImGuiComboFlags_NoPreview;
1469
1470 // Override default popup height
1471 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
1472 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1473 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
1474 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1475 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
1476 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1477
1478 // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1479 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1480 // stored in the object itself, etc.)
1481 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1482 static int item_selected_idx = 0; // Here we store our selection data as an index.
1483
1484 // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1485 const char* combo_preview_value = items[item_selected_idx];
1486
1487 if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1488 {
1489 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1490 {
1491 const bool is_selected = (item_selected_idx == n);
1492 if (ImGui::Selectable(items[n], is_selected))
1493 item_selected_idx = n;
1494
1495 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1496 if (is_selected)
1497 ImGui::SetItemDefaultFocus();
1498 }
1499 ImGui::EndCombo();
1500 }
1501
1502 ImGui::Spacing();
1503 ImGui::SeparatorText("One-liner variants");
1504 HelpMarker("Flags above don't apply to this section.");
1505
1506 // Simplified one-liner Combo() API, using values packed in a single constant string
1507 // This is a convenience for when the selection set is small and known at compile-time.
1508 static int item_current_2 = 0;
1509 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1510
1511 // Simplified one-liner Combo() using an array of const char*
1512 // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1513 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1514 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
1515
1516 // Simplified one-liner Combo() using an accessor function
1517 static int item_current_4 = 0;
1518 ImGui::Combo("combo 4 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items));
1519
1520 ImGui::TreePop();
1521 }
1522
1523 IMGUI_DEMO_MARKER("Widgets/List Boxes");
1524 if (ImGui::TreeNode("List boxes"))
1525 {
1526 // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
1527 // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
1528 // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
1529 // to always be called (inconsistent with BeginListBox()/EndListBox()).
1530
1531 // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1532 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1533 // stored in the object itself, etc.)
1534 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1535 static int item_selected_idx = 0; // Here we store our selected data as an index.
1536
1537 static bool item_highlight = false;
1538 int item_highlighted_idx = -1; // Here we store our highlighted data as an index.
1539 ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight);
1540
1541 if (ImGui::BeginListBox("listbox 1"))
1542 {
1543 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1544 {
1545 const bool is_selected = (item_selected_idx == n);
1546 if (ImGui::Selectable(items[n], is_selected))
1547 item_selected_idx = n;
1548
1549 if (item_highlight && ImGui::IsItemHovered())
1550 item_highlighted_idx = n;
1551
1552 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1553 if (is_selected)
1554 ImGui::SetItemDefaultFocus();
1555 }
1556 ImGui::EndListBox();
1557 }
1558 ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes.");
1559
1560 // Custom size: use all width, 5 items tall
1561 ImGui::Text("Full-width:");
1562 if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1563 {
1564 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1565 {
1566 bool is_selected = (item_selected_idx == n);
1567 ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0;
1568 if (ImGui::Selectable(items[n], is_selected, flags))
1569 item_selected_idx = n;
1570
1571 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1572 if (is_selected)
1573 ImGui::SetItemDefaultFocus();
1574 }
1575 ImGui::EndListBox();
1576 }
1577
1578 ImGui::TreePop();
1579 }
1580
1581 IMGUI_DEMO_MARKER("Widgets/Selectables");
1582 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
1583 if (ImGui::TreeNode("Selectables"))
1584 {
1585 // Selectable() has 2 overloads:
1586 // - The one taking "bool selected" as a read-only selection information.
1587 // When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1588 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1589 // The earlier is more flexible, as in real application your selection may be stored in many different ways
1590 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1591 IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
1592 if (ImGui::TreeNode("Basic"))
1593 {
1594 static bool selection[5] = { false, true, false, false };
1595 ImGui::Selectable("1. I am selectable", &selection[0]);
1596 ImGui::Selectable("2. I am selectable", &selection[1]);
1597 ImGui::Selectable("3. I am selectable", &selection[2]);
1598 if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
1599 if (ImGui::IsMouseDoubleClicked(0))
1600 selection[3] = !selection[3];
1601 ImGui::TreePop();
1602 }
1603
1604 IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
1605 if (ImGui::TreeNode("Rendering more items on the same line"))
1606 {
1607 // (1) Using SetNextItemAllowOverlap()
1608 // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
1609 static bool selected[3] = { false, false, false };
1610 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
1611 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
1612 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
1613 ImGui::TreePop();
1614 }
1615
1616 IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables");
1617 if (ImGui::TreeNode("In Tables"))
1618 {
1619 static bool selected[10] = {};
1620
1621 if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1622 {
1623 for (int i = 0; i < 10; i++)
1624 {
1625 char label[32];
1626 sprintf(label, "Item %d", i);
1627 ImGui::TableNextColumn();
1628 ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
1629 }
1630 ImGui::EndTable();
1631 }
1632 ImGui::Spacing();
1633 if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1634 {
1635 for (int i = 0; i < 10; i++)
1636 {
1637 char label[32];
1638 sprintf(label, "Item %d", i);
1639 ImGui::TableNextRow();
1640 ImGui::TableNextColumn();
1641 ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
1642 ImGui::TableNextColumn();
1643 ImGui::Text("Some other contents");
1644 ImGui::TableNextColumn();
1645 ImGui::Text("123456");
1646 }
1647 ImGui::EndTable();
1648 }
1649 ImGui::TreePop();
1650 }
1651
1652 IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
1653 if (ImGui::TreeNode("Grid"))
1654 {
1655 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
1656
1657 // Add in a bit of silly fun...
1658 const float time = (float)ImGui::GetTime();
1659 const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
1660 if (winning_state)
1661 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
1662
1663 for (int y = 0; y < 4; y++)
1664 for (int x = 0; x < 4; x++)
1665 {
1666 if (x > 0)
1667 ImGui::SameLine();
1668 ImGui::PushID(y * 4 + x);
1669 if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
1670 {
1671 // Toggle clicked cell + toggle neighbors
1672 selected[y][x] ^= 1;
1673 if (x > 0) { selected[y][x - 1] ^= 1; }
1674 if (x < 3) { selected[y][x + 1] ^= 1; }
1675 if (y > 0) { selected[y - 1][x] ^= 1; }
1676 if (y < 3) { selected[y + 1][x] ^= 1; }
1677 }
1678 ImGui::PopID();
1679 }
1680
1681 if (winning_state)
1682 ImGui::PopStyleVar();
1683 ImGui::TreePop();
1684 }
1685 IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
1686 if (ImGui::TreeNode("Alignment"))
1687 {
1688 HelpMarker(
1689 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1690 "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1691 "left-align otherwise it becomes difficult to layout multiple items on a same line");
1692 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1693 for (int y = 0; y < 3; y++)
1694 {
1695 for (int x = 0; x < 3; x++)
1696 {
1697 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1698 char name[32];
1699 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
1700 if (x > 0) ImGui::SameLine();
1701 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
1702 ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
1703 ImGui::PopStyleVar();
1704 }
1705 }
1706 ImGui::TreePop();
1707 }
1708 ImGui::TreePop();
1709 }
1710
1711 ShowDemoWindowMultiSelect(demo_data);
1712
1713 // To wire InputText() with std::string or any other custom string type,
1714 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1715 IMGUI_DEMO_MARKER("Widgets/Text Input");
1716 if (ImGui::TreeNode("Text Input"))
1717 {
1718 IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
1719 if (ImGui::TreeNode("Multi-line Text Input"))
1720 {
1721 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1722 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1723 static char text[1024 * 16] =
1724 "/*\n"
1725 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1726 " the hexadecimal encoding of one offending instruction,\n"
1727 " more formally, the invalid operand with locked CMPXCHG8B\n"
1728 " instruction bug, is a design flaw in the majority of\n"
1729 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1730 " processors (all in the P5 microarchitecture).\n"
1731 "*/\n\n"
1732 "label:\n"
1733 "\tlock cmpxchg8b eax\n";
1734
1735 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1736 HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include <string> in here)");
1737 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1738 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
1739 ImGui::SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.");
1740 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
1741 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1742 ImGui::TreePop();
1743 }
1744
1745 IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
1746 if (ImGui::TreeNode("Filtered Text Input"))
1747 {
1748 struct TextFilters
1749 {
1750 // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
1751 static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
1752 {
1753 if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
1754 else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
1755 return 0;
1756 }
1757
1758 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
1759 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1760 {
1761 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
1762 return 0;
1763 return 1;
1764 }
1765 };
1766
1767 static char buf1[32] = ""; ImGui::InputText("default", buf1, 32);
1768 static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal);
1769 static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1770 static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase);
1771 static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank);
1772 static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
1773 static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
1774 ImGui::TreePop();
1775 }
1776
1777 IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
1778 if (ImGui::TreeNode("Password Input"))
1779 {
1780 static char password[64] = "password123";
1781 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1782 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1783 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1784 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
1785 ImGui::TreePop();
1786 }
1787
1788 IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
1789 if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
1790 {
1791 struct Funcs
1792 {
1793 static int MyCallback(ImGuiInputTextCallbackData* data)
1794 {
1795 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1796 {
1797 data->InsertChars(data->CursorPos, "..");
1798 }
1799 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1800 {
1801 if (data->EventKey == ImGuiKey_UpArrow)
1802 {
1803 data->DeleteChars(0, data->BufTextLen);
1804 data->InsertChars(0, "Pressed Up!");
1805 data->SelectAll();
1806 }
1807 else if (data->EventKey == ImGuiKey_DownArrow)
1808 {
1809 data->DeleteChars(0, data->BufTextLen);
1810 data->InsertChars(0, "Pressed Down!");
1811 data->SelectAll();
1812 }
1813 }
1814 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1815 {
1816 // Toggle casing of first character
1817 char c = data->Buf[0];
1818 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1819 data->BufDirty = true;
1820
1821 // Increment a counter
1822 int* p_int = (int*)data->UserData;
1823 *p_int = *p_int + 1;
1824 }
1825 return 0;
1826 }
1827 };
1828 static char buf1[64];
1829 ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
1830 ImGui::SameLine(); HelpMarker(
1831 "Here we append \"..\" each time Tab is pressed. "
1832 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1833
1834 static char buf2[64];
1835 ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
1836 ImGui::SameLine(); HelpMarker(
1837 "Here we replace and select text each time Up/Down are pressed. "
1838 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1839
1840 static char buf3[64];
1841 static int edit_count = 0;
1842 ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
1843 ImGui::SameLine(); HelpMarker(
1844 "Here we toggle the casing of the first character on every edit + count edits.");
1845 ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
1846
1847 ImGui::TreePop();
1848 }
1849
1850 IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
1851 if (ImGui::TreeNode("Resize Callback"))
1852 {
1853 // To wire InputText() with std::string or any other custom string type,
1854 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1855 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1856 HelpMarker(
1857 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1858 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1859 struct Funcs
1860 {
1861 static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1862 {
1863 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1864 {
1865 ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1866 IM_ASSERT(my_str->begin() == data->Buf);
1867 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1868 data->Buf = my_str->begin();
1869 }
1870 return 0;
1871 }
1872
1873 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1874 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1875 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1876 {
1877 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1878 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
1879 }
1880 };
1881
1882 // For this demo we are using ImVector as a string container.
1883 // Note that because we need to store a terminating zero character, our size/capacity are 1 more
1884 // than usually reported by a typical string class.
1885 static ImVector<char> my_str;
1886 if (my_str.empty())
1887 my_str.push_back(0);
1888 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1889 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1890 ImGui::TreePop();
1891 }
1892
1893 IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment");
1894 if (ImGui::TreeNode("Eliding, Alignment"))
1895 {
1896 static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp";
1897 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft;
1898 ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft);
1899 ImGui::InputText("Path", buf1, IM_ARRAYSIZE(buf1), flags);
1900 ImGui::TreePop();
1901 }
1902
1903 IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
1904 if (ImGui::TreeNode("Miscellaneous"))
1905 {
1906 static char buf1[16];
1907 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
1908 ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
1909 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1910 ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
1911 ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags);
1912 ImGui::TreePop();
1913 }
1914
1915 ImGui::TreePop();
1916 }
1917
1918 // Tabs
1919 IMGUI_DEMO_MARKER("Widgets/Tabs");
1920 if (ImGui::TreeNode("Tabs"))
1921 {
1922 IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
1923 if (ImGui::TreeNode("Basic"))
1924 {
1925 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1926 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1927 {
1928 if (ImGui::BeginTabItem("Avocado"))
1929 {
1930 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
1931 ImGui::EndTabItem();
1932 }
1933 if (ImGui::BeginTabItem("Broccoli"))
1934 {
1935 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
1936 ImGui::EndTabItem();
1937 }
1938 if (ImGui::BeginTabItem("Cucumber"))
1939 {
1940 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
1941 ImGui::EndTabItem();
1942 }
1943 ImGui::EndTabBar();
1944 }
1945 ImGui::Separator();
1946 ImGui::TreePop();
1947 }
1948
1949 IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
1950 if (ImGui::TreeNode("Advanced & Close Button"))
1951 {
1952 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1953 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1954 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
1955 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
1956 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1957 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1958 ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
1959 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1960 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1961 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1962 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1963 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1964 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1965
1966 // Tab Bar
1967 ImGui::AlignTextToFramePadding();
1968 ImGui::Text("Opened:");
1969 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1970 static bool opened[4] = { true, true, true, true }; // Persistent user state
1971 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1972 {
1973 ImGui::SameLine();
1974 ImGui::Checkbox(names[n], &opened[n]);
1975 }
1976
1977 // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
1978 // the underlying bool will be set to false when the tab is closed.
1979 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1980 {
1981 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1982 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
1983 {
1984 ImGui::Text("This is the %s tab!", names[n]);
1985 if (n & 1)
1986 ImGui::Text("I am an odd tab.");
1987 ImGui::EndTabItem();
1988 }
1989 ImGui::EndTabBar();
1990 }
1991 ImGui::Separator();
1992 ImGui::TreePop();
1993 }
1994
1995 IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
1996 if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
1997 {
1998 static ImVector<int> active_tabs;
1999 static int next_tab_id = 0;
2000 if (next_tab_id == 0) // Initialize with some default tabs
2001 for (int i = 0; i < 3; i++)
2002 active_tabs.push_back(next_tab_id++);
2003
2004 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
2005 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
2006 // but they tend to make more sense together)
2007 static bool show_leading_button = true;
2008 static bool show_trailing_button = true;
2009 ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
2010 ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
2011
2012 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
2013 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
2014 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
2015 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
2016 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
2017 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
2018 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
2019
2020 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
2021 {
2022 // Demo a Leading TabItemButton(): click the "?" button to open a menu
2023 if (show_leading_button)
2024 if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
2025 ImGui::OpenPopup("MyHelpMenu");
2026 if (ImGui::BeginPopup("MyHelpMenu"))
2027 {
2028 ImGui::Selectable("Hello!");
2029 ImGui::EndPopup();
2030 }
2031
2032 // Demo Trailing Tabs: click the "+" button to add a new tab.
2033 // (In your app you may want to use a font icon instead of the "+")
2034 // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
2035 if (show_trailing_button)
2036 if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
2037 active_tabs.push_back(next_tab_id++); // Add new tab
2038
2039 // Submit our regular tabs
2040 for (int n = 0; n < active_tabs.Size; )
2041 {
2042 bool open = true;
2043 char name[16];
2044 snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
2045 if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
2046 {
2047 ImGui::Text("This is the %s tab!", name);
2048 ImGui::EndTabItem();
2049 }
2050
2051 if (!open)
2052 active_tabs.erase(active_tabs.Data + n);
2053 else
2054 n++;
2055 }
2056
2057 ImGui::EndTabBar();
2058 }
2059 ImGui::Separator();
2060 ImGui::TreePop();
2061 }
2062 ImGui::TreePop();
2063 }
2064
2065 // Plot/Graph widgets are not very good.
2066 // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
2067 // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
2068 IMGUI_DEMO_MARKER("Widgets/Plotting");
2069 if (ImGui::TreeNode("Plotting"))
2070 {
2071 static bool animate = true;
2072 ImGui::Checkbox("Animate", &animate);
2073
2074 // Plot as lines and plot as histogram
2075 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
2076 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
2077 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
2078 //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
2079
2080 // Fill an array of contiguous float values to plot
2081 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
2082 // and the sizeof() of your structure in the "stride" parameter.
2083 static float values[90] = {};
2084 static int values_offset = 0;
2085 static double refresh_time = 0.0;
2086 if (!animate || refresh_time == 0.0)
2087 refresh_time = ImGui::GetTime();
2088 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
2089 {
2090 static float phase = 0.0f;
2091 values[values_offset] = cosf(phase);
2092 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
2093 phase += 0.10f * values_offset;
2094 refresh_time += 1.0f / 60.0f;
2095 }
2096
2097 // Plots can display overlay texts
2098 // (in this example, we will display an average value)
2099 {
2100 float average = 0.0f;
2101 for (int n = 0; n < IM_ARRAYSIZE(values); n++)
2102 average += values[n];
2103 average /= (float)IM_ARRAYSIZE(values);
2104 char overlay[32];
2105 sprintf(overlay, "avg %f", average);
2106 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
2107 }
2108
2109 // Use functions to generate output
2110 // FIXME: This is actually VERY awkward because current plot API only pass in indices.
2111 // We probably want an API passing floats and user provide sample rate/count.
2112 struct Funcs
2113 {
2114 static float Sin(void*, int i) { return sinf(i * 0.1f); }
2115 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
2116 };
2117 static int func_type = 0, display_count = 70;
2118 ImGui::SeparatorText("Functions");
2119 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2120 ImGui::Combo("func", &func_type, "Sin\0Saw\0");
2121 ImGui::SameLine();
2122 ImGui::SliderInt("Sample count", &display_count, 1, 400);
2123 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
2124 ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2125 ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
2126 ImGui::Separator();
2127
2128 ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
2129 ImGui::TextLinkOpenURL("https://github.com/epezent/implot");
2130 ImGui::Separator();
2131
2132 ImGui::TreePop();
2133 }
2134
2135 IMGUI_DEMO_MARKER("Widgets/Progress Bars");
2136 if (ImGui::TreeNode("Progress Bars"))
2137 {
2138 // Animate a simple progress bar
2139 static float progress = 0.0f, progress_dir = 1.0f;
2140 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
2141 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
2142 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
2143
2144 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
2145 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
2146 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
2147 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2148 ImGui::Text("Progress Bar");
2149
2150 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
2151 char buf[32];
2152 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
2153 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
2154
2155 // Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value.
2156 // Adjust the factor if you want to adjust the animation speed.
2157 ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching..");
2158 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
2159 ImGui::Text("Indeterminate");
2160
2161 ImGui::TreePop();
2162 }
2163
2164 IMGUI_DEMO_MARKER("Widgets/Color");
2165 if (ImGui::TreeNode("Color/Picker Widgets"))
2166 {
2167 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
2168
2169 static bool alpha_preview = true;
2170 static bool alpha_half_preview = false;
2171 static bool drag_and_drop = true;
2172 static bool options_menu = true;
2173 static bool hdr = false;
2174 ImGui::SeparatorText("Options");
2175 ImGui::Checkbox("With Alpha Preview", &alpha_preview);
2176 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
2177 ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
2178 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
2179 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
2180 ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
2181
2182 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
2183 ImGui::SeparatorText("Inline color editor");
2184 ImGui::Text("Color widget:");
2185 ImGui::SameLine(); HelpMarker(
2186 "Click on the color square to open a color picker.\n"
2187 "CTRL+click on individual component to input value.\n");
2188 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
2189
2190 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
2191 ImGui::Text("Color widget HSV with Alpha:");
2192 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
2193
2194 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
2195 ImGui::Text("Color widget with Float Display:");
2196 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
2197
2198 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
2199 ImGui::Text("Color button with Picker:");
2200 ImGui::SameLine(); HelpMarker(
2201 "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
2202 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
2203 "be used for the tooltip and picker popup.");
2204 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
2205
2206 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
2207 ImGui::Text("Color button with Custom Picker Popup:");
2208
2209 // Generate a default palette. The palette will persist and can be edited.
2210 static bool saved_palette_init = true;
2211 static ImVec4 saved_palette[32] = {};
2212 if (saved_palette_init)
2213 {
2214 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2215 {
2216 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
2217 saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
2218 saved_palette[n].w = 1.0f; // Alpha
2219 }
2220 saved_palette_init = false;
2221 }
2222
2223 static ImVec4 backup_color;
2224 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
2225 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
2226 open_popup |= ImGui::Button("Palette");
2227 if (open_popup)
2228 {
2229 ImGui::OpenPopup("mypicker");
2230 backup_color = color;
2231 }
2232 if (ImGui::BeginPopup("mypicker"))
2233 {
2234 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
2235 ImGui::Separator();
2236 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
2237 ImGui::SameLine();
2238
2239 ImGui::BeginGroup(); // Lock X position
2240 ImGui::Text("Current");
2241 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
2242 ImGui::Text("Previous");
2243 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
2244 color = backup_color;
2245 ImGui::Separator();
2246 ImGui::Text("Palette");
2247 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2248 {
2249 ImGui::PushID(n);
2250 if ((n % 8) != 0)
2251 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
2252
2253 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
2254 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
2255 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
2256
2257 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
2258 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
2259 if (ImGui::BeginDragDropTarget())
2260 {
2261 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
2262 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
2263 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
2264 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
2265 ImGui::EndDragDropTarget();
2266 }
2267
2268 ImGui::PopID();
2269 }
2270 ImGui::EndGroup();
2271 ImGui::EndPopup();
2272 }
2273
2274 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
2275 ImGui::Text("Color button only:");
2276 static bool no_border = false;
2277 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
2278 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
2279
2280 IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
2281 ImGui::SeparatorText("Color picker");
2282 static bool alpha = true;
2283 static bool alpha_bar = true;
2284 static bool side_preview = true;
2285 static bool ref_color = false;
2286 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
2287 static int display_mode = 0;
2288 static int picker_mode = 0;
2289 ImGui::Checkbox("With Alpha", &alpha);
2290 ImGui::Checkbox("With Alpha Bar", &alpha_bar);
2291 ImGui::Checkbox("With Side Preview", &side_preview);
2292 if (side_preview)
2293 {
2294 ImGui::SameLine();
2295 ImGui::Checkbox("With Ref Color", &ref_color);
2296 if (ref_color)
2297 {
2298 ImGui::SameLine();
2299 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
2300 }
2301 }
2302 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
2303 ImGui::SameLine(); HelpMarker(
2304 "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
2305 "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
2306 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
2307 ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
2308 ImGuiColorEditFlags flags = misc_flags;
2309 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
2310 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
2311 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
2312 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
2313 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
2314 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
2315 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
2316 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
2317 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
2318 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
2319
2320 ImGui::Text("Set defaults in code:");
2321 ImGui::SameLine(); HelpMarker(
2322 "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
2323 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
2324 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
2325 "encouraging you to persistently save values that aren't forward-compatible.");
2326 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
2327 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
2328 if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
2329 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
2330
2331 // Always display a small version of both types of pickers
2332 // (that's in order to make it more visible in the demo to people who are skimming quickly through it)
2333 ImGui::Text("Both types:");
2334 float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
2335 ImGui::SetNextItemWidth(w);
2336 ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2337 ImGui::SameLine();
2338 ImGui::SetNextItemWidth(w);
2339 ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2340
2341 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
2342 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
2343 ImGui::Spacing();
2344 ImGui::Text("HSV encoded colors");
2345 ImGui::SameLine(); HelpMarker(
2346 "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
2347 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
2348 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
2349 ImGui::Text("Color widget with InputHSV:");
2350 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2351 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2352 ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
2353
2354 ImGui::TreePop();
2355 }
2356
2357 IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
2358 if (ImGui::TreeNode("Drag/Slider Flags"))
2359 {
2360 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
2361 static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
2362 ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
2363 ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput);
2364 ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.");
2365 ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange);
2366 ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.");
2367 ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
2368 ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
2369 ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
2370 ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
2371 ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
2372 ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
2373 ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
2374 ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
2375
2376 // Drags
2377 static float drag_f = 0.5f;
2378 static int drag_i = 50;
2379 ImGui::Text("Underlying float value: %f", drag_f);
2380 ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
2381 ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
2382 ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
2383 ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
2384 //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange
2385 //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
2386 ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
2387
2388 // Sliders
2389 static float slider_f = 0.5f;
2390 static int slider_i = 50;
2391 const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround;
2392 ImGui::Text("Underlying float value: %f", slider_f);
2393 ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
2394 ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
2395
2396 ImGui::TreePop();
2397 }
2398
2399 IMGUI_DEMO_MARKER("Widgets/Range Widgets");
2400 if (ImGui::TreeNode("Range Widgets"))
2401 {
2402 static float begin = 10, end = 90;
2403 static int begin_i = 100, end_i = 1000;
2404 ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
2405 ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
2406 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
2407 ImGui::TreePop();
2408 }
2409
2410 IMGUI_DEMO_MARKER("Widgets/Data Types");
2411 if (ImGui::TreeNode("Data Types"))
2412 {
2413 // DragScalar/InputScalar/SliderScalar functions allow various data types
2414 // - signed/unsigned
2415 // - 8/16/32/64-bits
2416 // - integer/float/double
2417 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
2418 // to pass the type, and passing all arguments by pointer.
2419 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
2420 // In practice, if you frequently use a given type that is not covered by the normal API entry points,
2421 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
2422 // and then pass their address to the generic function. For example:
2423 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
2424 // {
2425 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
2426 // }
2427
2428 // Setup limits (as helper variables so we can take their address, as explained above)
2429 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
2430 #ifndef LLONG_MIN
2431 ImS64 LLONG_MIN = -9223372036854775807LL - 1;
2432 ImS64 LLONG_MAX = 9223372036854775807LL;
2433 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
2434 #endif
2435 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
2436 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
2437 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
2438 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
2439 const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2;
2440 const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2;
2441 const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2;
2442 const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2;
2443 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
2444 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
2445
2446 // State
2447 static char s8_v = 127;
2448 static ImU8 u8_v = 255;
2449 static short s16_v = 32767;
2450 static ImU16 u16_v = 65535;
2451 static ImS32 s32_v = -1;
2452 static ImU32 u32_v = (ImU32)-1;
2453 static ImS64 s64_v = -1;
2454 static ImU64 u64_v = (ImU64)-1;
2455 static float f32_v = 0.123f;
2456 static double f64_v = 90000.01234567890123456789;
2457
2458 const float drag_speed = 0.2f;
2459 static bool drag_clamp = false;
2460 IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
2461 ImGui::SeparatorText("Drags");
2462 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
2463 ImGui::SameLine(); HelpMarker(
2464 "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
2465 "You can override the clamping limits by using CTRL+Click to input a value.");
2466 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
2467 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
2468 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
2469 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
2470 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
2471 ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
2472 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
2473 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
2474 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
2475 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
2476 ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
2477 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
2478 ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
2479
2480 IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
2481 ImGui::SeparatorText("Sliders");
2482 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
2483 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
2484 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
2485 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
2486 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
2487 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
2488 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
2489 ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X");
2490 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
2491 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
2492 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
2493 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
2494 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
2495 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64);
2496 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
2497 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
2498 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms");
2499 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
2500 ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2501 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
2502 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
2503 ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2504 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
2505
2506 ImGui::SeparatorText("Sliders (reverse)");
2507 ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
2508 ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
2509 ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
2510 ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
2511 ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
2512 ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
2513
2514 IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
2515 static bool inputs_step = true;
2516 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
2517 ImGui::SeparatorText("Inputs");
2518 ImGui::Checkbox("Show step buttons", &inputs_step);
2519 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
2520 ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal);
2521 ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal);
2522 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags);
2523 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags);
2524 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags);
2525 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags);
2526 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags);
2527 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags);
2528 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags);
2529 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags);
2530 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags);
2531 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags);
2532 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags);
2533 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags);
2534
2535 ImGui::TreePop();
2536 }
2537
2538 IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
2539 if (ImGui::TreeNode("Multi-component Widgets"))
2540 {
2541 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2542 static int vec4i[4] = { 1, 5, 100, 255 };
2543
2544 ImGui::SeparatorText("2-wide");
2545 ImGui::InputFloat2("input float2", vec4f);
2546 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
2547 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
2548 ImGui::InputInt2("input int2", vec4i);
2549 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
2550 ImGui::SliderInt2("slider int2", vec4i, 0, 255);
2551
2552 ImGui::SeparatorText("3-wide");
2553 ImGui::InputFloat3("input float3", vec4f);
2554 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
2555 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
2556 ImGui::InputInt3("input int3", vec4i);
2557 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
2558 ImGui::SliderInt3("slider int3", vec4i, 0, 255);
2559
2560 ImGui::SeparatorText("4-wide");
2561 ImGui::InputFloat4("input float4", vec4f);
2562 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
2563 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
2564 ImGui::InputInt4("input int4", vec4i);
2565 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
2566 ImGui::SliderInt4("slider int4", vec4i, 0, 255);
2567
2568 ImGui::TreePop();
2569 }
2570
2571 IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
2572 if (ImGui::TreeNode("Vertical Sliders"))
2573 {
2574 const float spacing = 4;
2575 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
2576
2577 static int int_value = 0;
2578 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
2579 ImGui::SameLine();
2580
2581 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
2582 ImGui::PushID("set1");
2583 for (int i = 0; i < 7; i++)
2584 {
2585 if (i > 0) ImGui::SameLine();
2586 ImGui::PushID(i);
2587 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
2588 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
2589 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
2590 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
2591 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
2592 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2593 ImGui::SetTooltip("%.3f", values[i]);
2594 ImGui::PopStyleColor(4);
2595 ImGui::PopID();
2596 }
2597 ImGui::PopID();
2598
2599 ImGui::SameLine();
2600 ImGui::PushID("set2");
2601 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
2602 const int rows = 3;
2603 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
2604 for (int nx = 0; nx < 4; nx++)
2605 {
2606 if (nx > 0) ImGui::SameLine();
2607 ImGui::BeginGroup();
2608 for (int ny = 0; ny < rows; ny++)
2609 {
2610 ImGui::PushID(nx * rows + ny);
2611 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
2612 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2613 ImGui::SetTooltip("%.3f", values2[nx]);
2614 ImGui::PopID();
2615 }
2616 ImGui::EndGroup();
2617 }
2618 ImGui::PopID();
2619
2620 ImGui::SameLine();
2621 ImGui::PushID("set3");
2622 for (int i = 0; i < 4; i++)
2623 {
2624 if (i > 0) ImGui::SameLine();
2625 ImGui::PushID(i);
2626 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
2627 ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
2628 ImGui::PopStyleVar();
2629 ImGui::PopID();
2630 }
2631 ImGui::PopID();
2632 ImGui::PopStyleVar();
2633 ImGui::TreePop();
2634 }
2635
2636 IMGUI_DEMO_MARKER("Widgets/Drag and drop");
2637 if (ImGui::TreeNode("Drag and Drop"))
2638 {
2639 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
2640 if (ImGui::TreeNode("Drag and drop in standard widgets"))
2641 {
2642 // ColorEdit widgets automatically act as drag source and drag target.
2643 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
2644 // to allow your own widgets to use colors in their drag and drop interaction.
2645 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
2646 HelpMarker("You can drag from the color squares.");
2647 static float col1[3] = { 1.0f, 0.0f, 0.2f };
2648 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
2649 ImGui::ColorEdit3("color 1", col1);
2650 ImGui::ColorEdit4("color 2", col2);
2651 ImGui::TreePop();
2652 }
2653
2654 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
2655 if (ImGui::TreeNode("Drag and drop to copy/swap items"))
2656 {
2657 enum Mode
2658 {
2659 Mode_Copy,
2660 Mode_Move,
2661 Mode_Swap
2662 };
2663 static int mode = 0;
2664 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
2665 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
2666 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
2667 static const char* names[9] =
2668 {
2669 "Bobby", "Beatrice", "Betty",
2670 "Brianna", "Barry", "Bernard",
2671 "Bibi", "Blaine", "Bryn"
2672 };
2673 for (int n = 0; n < IM_ARRAYSIZE(names); n++)
2674 {
2675 ImGui::PushID(n);
2676 if ((n % 3) != 0)
2677 ImGui::SameLine();
2678 ImGui::Button(names[n], ImVec2(60, 60));
2679
2680 // Our buttons are both drag sources and drag targets here!
2681 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
2682 {
2683 // Set payload to carry the index of our item (could be anything)
2684 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
2685
2686 // Display preview (could be anything, e.g. when dragging an image we could decide to display
2687 // the filename and a small preview of the image, etc.)
2688 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
2689 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
2690 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
2691 ImGui::EndDragDropSource();
2692 }
2693 if (ImGui::BeginDragDropTarget())
2694 {
2695 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
2696 {
2697 IM_ASSERT(payload->DataSize == sizeof(int));
2698 int payload_n = *(const int*)payload->Data;
2699 if (mode == Mode_Copy)
2700 {
2701 names[n] = names[payload_n];
2702 }
2703 if (mode == Mode_Move)
2704 {
2705 names[n] = names[payload_n];
2706 names[payload_n] = "";
2707 }
2708 if (mode == Mode_Swap)
2709 {
2710 const char* tmp = names[n];
2711 names[n] = names[payload_n];
2712 names[payload_n] = tmp;
2713 }
2714 }
2715 ImGui::EndDragDropTarget();
2716 }
2717 ImGui::PopID();
2718 }
2719 ImGui::TreePop();
2720 }
2721
2722 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
2723 if (ImGui::TreeNode("Drag to reorder items (simple)"))
2724 {
2725 // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
2726 // This code was always slightly faulty but in a way which was not easily noticeable.
2727 // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
2728 ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
2729
2730 // Simple reordering
2731 HelpMarker(
2732 "We don't use the drag and drop api at all here! "
2733 "Instead we query when the item is held but not hovered, and order items accordingly.");
2734 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
2735 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
2736 {
2737 const char* item = item_names[n];
2738 ImGui::Selectable(item);
2739
2740 if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
2741 {
2742 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
2743 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
2744 {
2745 item_names[n] = item_names[n_next];
2746 item_names[n_next] = item;
2747 ImGui::ResetMouseDragDelta();
2748 }
2749 }
2750 }
2751
2752 ImGui::PopItemFlag();
2753 ImGui::TreePop();
2754 }
2755
2756 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
2757 if (ImGui::TreeNode("Tooltip at target location"))
2758 {
2759 for (int n = 0; n < 2; n++)
2760 {
2761 // Drop targets
2762 ImGui::Button(n ? "drop here##1" : "drop here##0");
2763 if (ImGui::BeginDragDropTarget())
2764 {
2765 ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
2766 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags))
2767 {
2768 IM_UNUSED(payload);
2769 ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
2770 ImGui::SetTooltip("Cannot drop here!");
2771 }
2772 ImGui::EndDragDropTarget();
2773 }
2774
2775 // Drop source
2776 static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
2777 if (n == 0)
2778 ImGui::ColorButton("drag me", col4);
2779
2780 }
2781 ImGui::TreePop();
2782 }
2783
2784 ImGui::TreePop();
2785 }
2786
2787 IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2788 if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)"))
2789 {
2790 // Select an item type
2791 const char* item_names[] =
2792 {
2793 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2794 "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2795 };
2796 static int item_type = 4;
2797 static bool item_disabled = false;
2798 ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
2799 ImGui::SameLine();
2800 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().");
2801 ImGui::Checkbox("Item Disabled", &item_disabled);
2802
2803 // Submit selected items so we can query their status in the code following it.
2804 bool ret = false;
2805 static bool b = false;
2806 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2807 static char str[16] = {};
2808 if (item_disabled)
2809 ImGui::BeginDisabled(true);
2810 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
2811 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
2812 if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater)
2813 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
2814 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
2815 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
2816 if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window)
2817 if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
2818 if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2819 if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2820 if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
2821 if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2822 if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
2823 if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2824 if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_ARRAYSIZE(items)); }
2825 if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
2826
2827 bool hovered_delay_none = ImGui::IsItemHovered();
2828 bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary);
2829 bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
2830 bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
2831 bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2832
2833 // Display the values of IsItemHovered() and other common item state functions.
2834 // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2835 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2836 // we query every state in a single call to avoid storing them and to simplify the code.
2837 ImGui::BulletText(
2838 "Return value = %d\n"
2839 "IsItemFocused() = %d\n"
2840 "IsItemHovered() = %d\n"
2841 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2842 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2843 "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2844 "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2845 "IsItemHovered(_AllowWhenDisabled) = %d\n"
2846 "IsItemHovered(_RectOnly) = %d\n"
2847 "IsItemActive() = %d\n"
2848 "IsItemEdited() = %d\n"
2849 "IsItemActivated() = %d\n"
2850 "IsItemDeactivated() = %d\n"
2851 "IsItemDeactivatedAfterEdit() = %d\n"
2852 "IsItemVisible() = %d\n"
2853 "IsItemClicked() = %d\n"
2854 "IsItemToggledOpen() = %d\n"
2855 "GetItemRectMin() = (%.1f, %.1f)\n"
2856 "GetItemRectMax() = (%.1f, %.1f)\n"
2857 "GetItemRectSize() = (%.1f, %.1f)",
2858 ret,
2859 ImGui::IsItemFocused(),
2860 ImGui::IsItemHovered(),
2861 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2862 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2863 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2864 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2865 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled),
2866 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2867 ImGui::IsItemActive(),
2868 ImGui::IsItemEdited(),
2869 ImGui::IsItemActivated(),
2870 ImGui::IsItemDeactivated(),
2871 ImGui::IsItemDeactivatedAfterEdit(),
2872 ImGui::IsItemVisible(),
2873 ImGui::IsItemClicked(),
2874 ImGui::IsItemToggledOpen(),
2875 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2876 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2877 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2878 );
2879 ImGui::BulletText(
2880 "with Hovering Delay or Stationary test:\n"
2881 "IsItemHovered() = = %d\n"
2882 "IsItemHovered(_Stationary) = %d\n"
2883 "IsItemHovered(_DelayShort) = %d\n"
2884 "IsItemHovered(_DelayNormal) = %d\n"
2885 "IsItemHovered(_Tooltip) = %d",
2886 hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2887
2888 if (item_disabled)
2889 ImGui::EndDisabled();
2890
2891 char buf[1] = "";
2892 ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly);
2893 ImGui::SameLine();
2894 HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2895
2896 ImGui::TreePop();
2897 }
2898
2899 IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2900 if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)"))
2901 {
2902 static bool embed_all_inside_a_child_window = false;
2903 ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
2904 if (embed_all_inside_a_child_window)
2905 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders);
2906
2907 // Testing IsWindowFocused() function with its various flags.
2908 ImGui::BulletText(
2909 "IsWindowFocused() = %d\n"
2910 "IsWindowFocused(_ChildWindows) = %d\n"
2911 "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2912 "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
2913 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2914 "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2915 "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2916 "IsWindowFocused(_RootWindow) = %d\n"
2917 "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2918 "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
2919 "IsWindowFocused(_AnyWindow) = %d\n",
2920 ImGui::IsWindowFocused(),
2921 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2922 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2923 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
2924 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2925 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2926 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2927 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2928 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2929 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2930 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2931
2932 // Testing IsWindowHovered() function with its various flags.
2933 ImGui::BulletText(
2934 "IsWindowHovered() = %d\n"
2935 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2936 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2937 "IsWindowHovered(_ChildWindows) = %d\n"
2938 "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2939 "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
2940 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2941 "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2942 "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2943 "IsWindowHovered(_RootWindow) = %d\n"
2944 "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2945 "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
2946 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2947 "IsWindowHovered(_AnyWindow) = %d\n"
2948 "IsWindowHovered(_Stationary) = %d\n",
2949 ImGui::IsWindowHovered(),
2950 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2951 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2952 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2953 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2954 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
2955 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2956 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2957 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2958 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2959 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2960 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2961 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2962 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
2963 ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
2964
2965 ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders);
2966 ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2967 ImGui::EndChild();
2968 if (embed_all_inside_a_child_window)
2969 ImGui::EndChild();
2970
2971 // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2972 // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2973 // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2974 static bool test_window = false;
2975 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2976 if (test_window)
2977 {
2978 // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2979 // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2980 ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2981 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2982 {
2983 if (ImGui::MenuItem("Close")) { test_window = false; }
2984 ImGui::EndPopup();
2985 }
2986 ImGui::Text(
2987 "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2988 "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2989 ImGui::IsItemHovered(), ImGui::IsItemActive());
2990 ImGui::End();
2991 }
2992
2993 ImGui::TreePop();
2994 }
2995
2996 // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd:
2997 // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space)
2998 if (disable_all)
2999 ImGui::EndDisabled();
3000
3001 IMGUI_DEMO_MARKER("Widgets/Disable Block");
3002 if (ImGui::TreeNode("Disable block"))
3003 {
3004 ImGui::Checkbox("Disable entire section above", &disable_all);
3005 ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section.");
3006 ImGui::TreePop();
3007 }
3008
3009 IMGUI_DEMO_MARKER("Widgets/Text Filter");
3010 if (ImGui::TreeNode("Text Filter"))
3011 {
3012 // Helper class to easy setup a text filter.
3013 // You may want to implement a more feature-full filtering scheme in your own application.
3014 HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
3015 static ImGuiTextFilter filter;
3016 ImGui::Text("Filter usage:\n"
3017 " \"\" display all lines\n"
3018 " \"xxx\" display lines containing \"xxx\"\n"
3019 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
3020 " \"-xxx\" hide lines containing \"xxx\"");
3021 filter.Draw();
3022 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
3023 for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
3024 if (filter.PassFilter(lines[i]))
3025 ImGui::BulletText("%s", lines[i]);
3026 ImGui::TreePop();
3027 }
3028}
3029
3030static const char* ExampleNames[] =
3031{
3032 "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
3033 "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
3034 "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
3035};
3036
3037// Extra functions to add deletion support to ImGuiSelectionBasicStorage
3038struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
3039{
3040 // Find which item should be Focused after deletion.
3041 // Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
3042 // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
3043 // - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
3044 // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
3045 // - Important: Deletion only works if the underlying ImGuiID for your items are stable: aka not depend on their index, but on e.g. item id/ptr.
3046 // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
3047 int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
3048 {
3049 if (Size == 0)
3050 return -1;
3051
3052 // If focused item is not selected...
3053 const int focused_idx = (int)ms_io->NavIdItem; // Index of currently focused item
3054 if (ms_io->NavIdSelected == false) // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx))
3055 {
3056 ms_io->RangeSrcReset = true; // Request to recover RangeSrc from NavId next frame. Would be ok to reset even when NavIdSelected==true, but it would take an extra frame to recover RangeSrc when deleting a selected item.
3057 return focused_idx; // Request to focus same item after deletion.
3058 }
3059
3060 // If focused item is selected: land on first unselected item after focused item.
3061 for (int idx = focused_idx + 1; idx < items_count; idx++)
3062 if (!Contains(GetStorageIdFromIndex(idx)))
3063 return idx;
3064
3065 // If focused item is selected: otherwise return last unselected item before focused item.
3066 for (int idx = IM_MIN(focused_idx, items_count) - 1; idx >= 0; idx--)
3067 if (!Contains(GetStorageIdFromIndex(idx)))
3068 return idx;
3069
3070 return -1;
3071 }
3072
3073 // Rewrite item list (delete items) + update selection.
3074 // - Call after EndMultiSelect()
3075 // - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
3076 template<typename ITEM_TYPE>
3077 void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items, int item_curr_idx_to_select)
3078 {
3079 // Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
3080 // If NavId was not part of selection, we will stay on same item.
3081 ImVector<ITEM_TYPE> new_items;
3082 new_items.reserve(items.Size - Size);
3083 int item_next_idx_to_select = -1;
3084 for (int idx = 0; idx < items.Size; idx++)
3085 {
3086 if (!Contains(GetStorageIdFromIndex(idx)))
3087 new_items.push_back(items[idx]);
3088 if (item_curr_idx_to_select == idx)
3089 item_next_idx_to_select = new_items.Size - 1;
3090 }
3091 items.swap(new_items);
3092
3093 // Update selection
3094 Clear();
3095 if (item_next_idx_to_select != -1 && ms_io->NavIdSelected)
3096 SetItemSelected(GetStorageIdFromIndex(item_next_idx_to_select), true);
3097 }
3098};
3099
3100// Example: Implement dual list box storage and interface
3102{
3103 ImVector<ImGuiID> Items[2]; // ID is index into ExampleName[]
3104 ImGuiSelectionBasicStorage Selections[2]; // Store ExampleItemId into selection
3105 bool OptKeepSorted = true;
3106
3107 void MoveAll(int src, int dst)
3108 {
3109 IM_ASSERT((src == 0 && dst == 1) || (src == 1 && dst == 0));
3110 for (ImGuiID item_id : Items[src])
3111 Items[dst].push_back(item_id);
3112 Items[src].clear();
3113 SortItems(dst);
3114 Selections[src].Swap(Selections[dst]);
3115 Selections[src].Clear();
3116 }
3117 void MoveSelected(int src, int dst)
3118 {
3119 for (int src_n = 0; src_n < Items[src].Size; src_n++)
3120 {
3121 ImGuiID item_id = Items[src][src_n];
3122 if (!Selections[src].Contains(item_id))
3123 continue;
3124 Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap)
3125 Items[dst].push_back(item_id);
3126 src_n--;
3127 }
3128 if (OptKeepSorted)
3129 SortItems(dst);
3130 Selections[src].Swap(Selections[dst]);
3131 Selections[src].Clear();
3132 }
3133 void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side)
3134 {
3135 // In this example we store item id in selection (instead of item index)
3136 Selections[side].UserData = Items[side].Data;
3137 Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
3138 Selections[side].ApplyRequests(ms_io);
3139 }
3140 static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
3141 {
3142 const int* a = (const int*)lhs;
3143 const int* b = (const int*)rhs;
3144 return (*a - *b) > 0 ? +1 : -1;
3145 }
3146 void SortItems(int n)
3147 {
3148 qsort(Items[n].Data, (size_t)Items[n].Size, sizeof(Items[n][0]), CompareItemsByValue);
3149 }
3150 void Show()
3151 {
3152 //ImGui::Checkbox("Sorted", &OptKeepSorted);
3153 if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None))
3154 {
3155 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side
3156 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); // Buttons
3157 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Right side
3158 ImGui::TableNextRow();
3159
3160 int request_move_selected = -1;
3161 int request_move_all = -1;
3162 float child_height_0 = 0.0f;
3163 for (int side = 0; side < 2; side++)
3164 {
3165 // FIXME-MULTISELECT: Dual List Box: Add context menus
3166 // FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues.
3167 ImVector<ImGuiID>& items = Items[side];
3168 ImGuiSelectionBasicStorage& selection = Selections[side];
3169
3170 ImGui::TableSetColumnIndex((side == 0) ? 0 : 2);
3171 ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size);
3172
3173 // Submit scrolling range to avoid glitches on moving/deletion
3174 const float items_height = ImGui::GetTextLineHeightWithSpacing();
3175 ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3176
3177 bool child_visible;
3178 if (side == 0)
3179 {
3180 // Left child is resizable
3181 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX));
3182 child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY);
3183 child_height_0 = ImGui::GetWindowSize().y;
3184 }
3185 else
3186 {
3187 // Right child use same height as left one
3188 child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle);
3189 }
3190 if (child_visible)
3191 {
3192 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
3193 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3194 ApplySelectionRequests(ms_io, side);
3195
3196 for (int item_n = 0; item_n < items.Size; item_n++)
3197 {
3198 ImGuiID item_id = items[item_n];
3199 bool item_is_selected = selection.Contains(item_id);
3200 ImGui::SetNextItemSelectionUserData(item_n);
3201 ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick);
3202 if (ImGui::IsItemFocused())
3203 {
3204 // FIXME-MULTISELECT: Dual List Box: Transfer focus
3205 if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
3206 request_move_selected = side;
3207 if (ImGui::IsMouseDoubleClicked(0)) // FIXME-MULTISELECT: Double-click on multi-selection?
3208 request_move_selected = side;
3209 }
3210 }
3211
3212 ms_io = ImGui::EndMultiSelect();
3213 ApplySelectionRequests(ms_io, side);
3214 }
3215 ImGui::EndChild();
3216 }
3217
3218 // Buttons columns
3219 ImGui::TableSetColumnIndex(1);
3220 ImGui::NewLine();
3221 //ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f };
3222 ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() };
3223
3224 // (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized)
3225 if (ImGui::Button(">>", button_sz))
3226 request_move_all = 0;
3227 if (ImGui::Button(">", button_sz))
3228 request_move_selected = 0;
3229 if (ImGui::Button("<", button_sz))
3230 request_move_selected = 1;
3231 if (ImGui::Button("<<", button_sz))
3232 request_move_all = 1;
3233
3234 // Process requests
3235 if (request_move_all != -1)
3236 MoveAll(request_move_all, request_move_all ^ 1);
3237 if (request_move_selected != -1)
3238 MoveSelected(request_move_selected, request_move_selected ^ 1);
3239
3240 // FIXME-MULTISELECT: Support action from outside
3241 /*
3242 if (OptKeepSorted == false)
3243 {
3244 ImGui::NewLine();
3245 if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {}
3246 if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {}
3247 }
3248 */
3249
3250 ImGui::EndTable();
3251 }
3252 }
3253};
3254
3255//-----------------------------------------------------------------------------
3256// [SECTION] ShowDemoWindowMultiSelect()
3257//-----------------------------------------------------------------------------
3258// Multi-selection demos
3259// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select
3260//-----------------------------------------------------------------------------
3261
3262static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data)
3263{
3264 IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select");
3265 if (ImGui::TreeNode("Selection State & Multi-Select"))
3266 {
3267 HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
3268
3269 // Without any fancy API: manage single-selection yourself.
3270 IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select");
3271 if (ImGui::TreeNode("Single-Select"))
3272 {
3273 static int selected = -1;
3274 for (int n = 0; n < 5; n++)
3275 {
3276 char buf[32];
3277 sprintf(buf, "Object %d", n);
3278 if (ImGui::Selectable(buf, selected == n))
3279 selected = n;
3280 }
3281 ImGui::TreePop();
3282 }
3283
3284 // Demonstrate implementation a most-basic form of multi-selection manually
3285 // This doesn't support the SHIFT modifier which requires BeginMultiSelect()!
3286 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)");
3287 if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)"))
3288 {
3289 HelpMarker("Hold CTRL and click to select multiple items.");
3290 static bool selection[5] = { false, false, false, false, false };
3291 for (int n = 0; n < 5; n++)
3292 {
3293 char buf[32];
3294 sprintf(buf, "Object %d", n);
3295 if (ImGui::Selectable(buf, selection[n]))
3296 {
3297 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
3298 memset(selection, 0, sizeof(selection));
3299 selection[n] ^= 1; // Toggle current item
3300 }
3301 }
3302 ImGui::TreePop();
3303 }
3304
3305 // Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API.
3306 // SHIFT+Click w/ CTRL and other standard features are supported.
3307 // We use the ImGuiSelectionBasicStorage helper which you may freely reimplement.
3308 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select");
3309 if (ImGui::TreeNode("Multi-Select"))
3310 {
3311 ImGui::Text("Supported features:");
3312 ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space).");
3313 ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
3314 ImGui::BulletText("Shift modifier for range selection.");
3315 ImGui::BulletText("CTRL+A to select all.");
3316 ImGui::BulletText("Escape to clear selection.");
3317 ImGui::BulletText("Click and drag to box-select.");
3318 ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
3319
3320 // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3321 const int ITEMS_COUNT = 50;
3322 static ImGuiSelectionBasicStorage selection;
3323 ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3324
3325 // The BeginChild() has no purpose for selection logic, other that offering a scrolling region.
3326 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3327 {
3328 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3329 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3330 selection.ApplyRequests(ms_io);
3331
3332 for (int n = 0; n < ITEMS_COUNT; n++)
3333 {
3334 char label[64];
3335 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3336 bool item_is_selected = selection.Contains((ImGuiID)n);
3337 ImGui::SetNextItemSelectionUserData(n);
3338 ImGui::Selectable(label, item_is_selected);
3339 }
3340
3341 ms_io = ImGui::EndMultiSelect();
3342 selection.ApplyRequests(ms_io);
3343 }
3344 ImGui::EndChild();
3345 ImGui::TreePop();
3346 }
3347
3348 // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3349 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
3350 if (ImGui::TreeNode("Multi-Select (with clipper)"))
3351 {
3352 // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3353 static ImGuiSelectionBasicStorage selection;
3354
3355 ImGui::Text("Added features:");
3356 ImGui::BulletText("Using ImGuiListClipper.");
3357
3358 const int ITEMS_COUNT = 10000;
3359 ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3360 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3361 {
3362 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3363 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3364 selection.ApplyRequests(ms_io);
3365
3366 ImGuiListClipper clipper;
3367 clipper.Begin(ITEMS_COUNT);
3368 if (ms_io->RangeSrcItem != -1)
3369 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3370 while (clipper.Step())
3371 {
3372 for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3373 {
3374 char label[64];
3375 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3376 bool item_is_selected = selection.Contains((ImGuiID)n);
3377 ImGui::SetNextItemSelectionUserData(n);
3378 ImGui::Selectable(label, item_is_selected);
3379 }
3380 }
3381
3382 ms_io = ImGui::EndMultiSelect();
3383 selection.ApplyRequests(ms_io);
3384 }
3385 ImGui::EndChild();
3386 ImGui::TreePop();
3387 }
3388
3389 // Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API.
3390 // In order to support Deletion without any glitches you need to:
3391 // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling.
3392 // - (2) Items needs to have persistent ID Stack identifier = ID needs to not depends on their index. PushID(index) = KO. PushID(item_id) = OK. This is in order to focus items reliably after a selection.
3393 // - (3) BeginXXXX process
3394 // - (4) Focus process
3395 // - (5) EndXXXX process
3396 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
3397 if (ImGui::TreeNode("Multi-Select (with deletion)"))
3398 {
3399 // Storing items data separately from selection data.
3400 // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
3401 // Use a custom selection.Adapter: store item identifier in Selection (instead of index)
3402 static ImVector<ImGuiID> items;
3403 static ExampleSelectionWithDeletion selection;
3404 selection.UserData = (void*)&items;
3405 selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->UserData; return (*p_items)[idx]; }; // Index -> ID
3406
3407 ImGui::Text("Added features:");
3408 ImGui::BulletText("Dynamic list with Delete key support.");
3409 ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3410
3411 // Initialize default list with 50 items + button to add/remove items.
3412 static ImGuiID items_next_id = 0;
3413 if (items_next_id == 0)
3414 for (ImGuiID n = 0; n < 50; n++)
3415 items.push_back(items_next_id++);
3416 if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
3417 ImGui::SameLine();
3418 if (ImGui::SmallButton("Remove 20 items")) { for (int n = IM_MIN(20, items.Size); n > 0; n--) { selection.SetItemSelected(items.back(), false); items.pop_back(); } }
3419
3420 // (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
3421 const float items_height = ImGui::GetTextLineHeightWithSpacing();
3422 ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3423
3424 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3425 {
3426 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3427 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3428 selection.ApplyRequests(ms_io);
3429
3430 const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
3431 const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3432
3433 for (int n = 0; n < items.Size; n++)
3434 {
3435 const ImGuiID item_id = items[n];
3436 char label[64];
3437 sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]);
3438
3439 bool item_is_selected = selection.Contains(item_id);
3440 ImGui::SetNextItemSelectionUserData(n);
3441 ImGui::Selectable(label, item_is_selected);
3442 if (item_curr_idx_to_focus == n)
3443 ImGui::SetKeyboardFocusHere(-1);
3444 }
3445
3446 // Apply multi-select requests
3447 ms_io = ImGui::EndMultiSelect();
3448 selection.ApplyRequests(ms_io);
3449 if (want_delete)
3450 selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3451 }
3452 ImGui::EndChild();
3453 ImGui::TreePop();
3454 }
3455
3456 // Implement a Dual List Box (#6648)
3457 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)");
3458 if (ImGui::TreeNode("Multi-Select (dual list box)"))
3459 {
3460 // Init default state
3461 static ExampleDualListBox dlb;
3462 if (dlb.Items[0].Size == 0 && dlb.Items[1].Size == 0)
3463 for (int item_id = 0; item_id < IM_ARRAYSIZE(ExampleNames); item_id++)
3464 dlb.Items[0].push_back((ImGuiID)item_id);
3465
3466 // Show
3467 dlb.Show();
3468
3469 ImGui::TreePop();
3470 }
3471
3472 // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
3473 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)");
3474 if (ImGui::TreeNode("Multi-Select (in a table)"))
3475 {
3476 static ImGuiSelectionBasicStorage selection;
3477
3478 const int ITEMS_COUNT = 10000;
3479 ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
3480 if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter))
3481 {
3482 ImGui::TableSetupColumn("Object");
3483 ImGui::TableSetupColumn("Action");
3484 ImGui::TableSetupScrollFreeze(0, 1);
3485 ImGui::TableHeadersRow();
3486
3487 ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3488 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
3489 selection.ApplyRequests(ms_io);
3490
3491 ImGuiListClipper clipper;
3492 clipper.Begin(ITEMS_COUNT);
3493 if (ms_io->RangeSrcItem != -1)
3494 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3495 while (clipper.Step())
3496 {
3497 for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
3498 {
3499 ImGui::TableNextRow();
3500 ImGui::TableNextColumn();
3501 char label[64];
3502 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3503 bool item_is_selected = selection.Contains((ImGuiID)n);
3504 ImGui::SetNextItemSelectionUserData(n);
3505 ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
3506 ImGui::TableNextColumn();
3507 ImGui::SmallButton("hello");
3508 }
3509 }
3510
3511 ms_io = ImGui::EndMultiSelect();
3512 selection.ApplyRequests(ms_io);
3513 ImGui::EndTable();
3514 }
3515 ImGui::TreePop();
3516 }
3517
3518 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)");
3519 if (ImGui::TreeNode("Multi-Select (checkboxes)"))
3520 {
3521 ImGui::Text("In a list of checkboxes (not selectable):");
3522 ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags.");
3523 ImGui::BulletText("Shift+Click to check multiple boxes.");
3524 ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
3525
3526 // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
3527 static bool items[20] = {};
3528 static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
3529 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3530 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3531 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
3532
3533 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
3534 {
3535 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items));
3536 ImGuiSelectionExternalStorage storage_wrapper;
3537 storage_wrapper.UserData = (void*)items;
3538 storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
3539 storage_wrapper.ApplyRequests(ms_io);
3540 for (int n = 0; n < 20; n++)
3541 {
3542 char label[32];
3543 sprintf(label, "Item %d", n);
3544 ImGui::SetNextItemSelectionUserData(n);
3545 ImGui::Checkbox(label, &items[n]);
3546 }
3547 ms_io = ImGui::EndMultiSelect();
3548 storage_wrapper.ApplyRequests(ms_io);
3549 }
3550 ImGui::EndChild();
3551
3552 ImGui::TreePop();
3553 }
3554
3555 // Demonstrate individual selection scopes in same window
3556 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)");
3557 if (ImGui::TreeNode("Multi-Select (multiple scopes)"))
3558 {
3559 // Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
3560 const int SCOPES_COUNT = 3;
3561 const int ITEMS_COUNT = 8; // Per scope
3562 static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT];
3563
3564 // Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
3565 static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid;
3566 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3567 flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3568 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3569 flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3570 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3571 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3572
3573 for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++)
3574 {
3575 ImGui::PushID(selection_scope_n);
3576 ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
3577 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
3578 selection->ApplyRequests(ms_io);
3579
3580 ImGui::SeparatorText("Selection scope");
3581 ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
3582
3583 for (int n = 0; n < ITEMS_COUNT; n++)
3584 {
3585 char label[64];
3586 sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
3587 bool item_is_selected = selection->Contains((ImGuiID)n);
3588 ImGui::SetNextItemSelectionUserData(n);
3589 ImGui::Selectable(label, item_is_selected);
3590 }
3591
3592 // Apply multi-select requests
3593 ms_io = ImGui::EndMultiSelect();
3594 selection->ApplyRequests(ms_io);
3595 ImGui::PopID();
3596 }
3597 ImGui::TreePop();
3598 }
3599
3600 // See ShowExampleAppAssetsBrowser()
3601 if (ImGui::TreeNode("Multi-Select (tiled assets browser)"))
3602 {
3603 ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser);
3604 ImGui::Text("(also access from 'Examples->Assets Browser' in menu)");
3605 ImGui::TreePop();
3606 }
3607
3608 // Demonstrate supporting multiple-selection in a tree.
3609 // - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly!
3610 // This showcase how SetNextItemSelectionUserData() never assume indices!
3611 // - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request.
3612 // We want this interpolation to match what the user sees: in visible order, skipping closed nodes.
3613 // This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper.
3614 // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you
3615 // are more likely to build an array mapping sequential indices to visible tree nodes, since your
3616 // filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier.
3617 // - Consider this a prototype: we are working toward simplifying some of it.
3618 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)");
3619 if (ImGui::TreeNode("Multi-Select (trees)"))
3620 {
3621 HelpMarker(
3622 "This is rather advanced and experimental. If you are getting started with multi-select,"
3623 "please don't start by looking at how to use it for a tree!\n\n"
3624 "Future versions will try to simplify and formalize some of this.");
3625
3626 struct ExampleTreeFuncs
3627 {
3628 static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection)
3629 {
3630 ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3631 tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent
3632 if (node->Childs.Size == 0)
3633 tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf;
3634 if (selection->Contains((ImGuiID)node->UID))
3635 tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3636
3637 // Using SetNextItemStorageID() to specify storage id, so we can easily peek into
3638 // the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions.
3639 ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node);
3640 ImGui::SetNextItemStorageID((ImGuiID)node->UID);
3641 if (ImGui::TreeNodeEx(node->Name, tree_node_flags))
3642 {
3643 for (ExampleTreeNode* child : node->Childs)
3644 DrawNode(child, selection);
3645 ImGui::TreePop();
3646 }
3647 else if (ImGui::IsItemToggledOpen())
3648 {
3649 TreeCloseAndUnselectChildNodes(node, selection);
3650 }
3651 }
3652
3653 static bool TreeNodeGetOpen(ExampleTreeNode* node)
3654 {
3655 return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID);
3656 }
3657
3658 static void TreeNodeSetOpen(ExampleTreeNode* node, bool open)
3659 {
3660 ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open);
3661 }
3662
3663 // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected.
3664 // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node
3665 // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc.
3666 static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0)
3667 {
3668 // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!)
3669 int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0;
3670 if (depth == 0 || TreeNodeGetOpen(node))
3671 {
3672 for (ExampleTreeNode* child : node->Childs)
3673 unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1);
3674 TreeNodeSetOpen(node, false);
3675 }
3676
3677 // Select root node if any of its child was selected, otherwise unselect
3678 selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0));
3679 return unselected_count;
3680 }
3681
3682 // Apply multi-selection requests
3683 static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection)
3684 {
3685 for (ImGuiSelectionRequest& req : ms_io->Requests)
3686 {
3687 if (req.Type == ImGuiSelectionRequestType_SetAll)
3688 {
3689 if (req.Selected)
3690 TreeSetAllInOpenNodes(tree, selection, req.Selected);
3691 else
3692 selection->Clear();
3693 }
3694 else if (req.Type == ImGuiSelectionRequestType_SetRange)
3695 {
3696 ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem;
3697 ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem;
3698 for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node))
3699 selection->SetItemSelected((ImGuiID)node->UID, req.Selected);
3700 }
3701 }
3702 }
3703
3704 static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected)
3705 {
3706 if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme
3707 selection->SetItemSelected((ImGuiID)node->UID, selected);
3708 if (node->Parent == NULL || TreeNodeGetOpen(node))
3709 for (ExampleTreeNode* child : node->Childs)
3710 TreeSetAllInOpenNodes(child, selection, selected);
3711 }
3712
3713 // Interpolate in *user-visible order* AND only *over opened nodes*.
3714 // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler.
3715 // Here the tricks are that:
3716 // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion.
3717 // this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)'
3718 // which would only be called when crossing from child to a parent, aka not too much.
3719 // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack,
3720 // making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location.
3721 static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node)
3722 {
3723 // Reached last node
3724 if (curr_node == last_node)
3725 return NULL;
3726
3727 // Recurse into childs. Query storage to tell if the node is open.
3728 if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node))
3729 return curr_node->Childs[0];
3730
3731 // Next sibling, then into our own parent
3732 while (curr_node->Parent != NULL)
3733 {
3734 if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size)
3735 return curr_node->Parent->Childs[curr_node->IndexInParent + 1];
3736 curr_node = curr_node->Parent;
3737 }
3738 return NULL;
3739 }
3740
3741 }; // ExampleTreeFuncs
3742
3743 static ImGuiSelectionBasicStorage selection;
3744 if (demo_data->DemoTree == NULL)
3745 demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once
3746 ImGui::Text("Selection size: %d", selection.Size);
3747
3748 if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3749 {
3750 ExampleTreeNode* tree = demo_data->DemoTree;
3751 ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d;
3752 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1);
3753 ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3754 for (ExampleTreeNode* node : tree->Childs)
3755 ExampleTreeFuncs::DrawNode(node, &selection);
3756 ms_io = ImGui::EndMultiSelect();
3757 ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
3758 }
3759 ImGui::EndChild();
3760
3761 ImGui::TreePop();
3762 }
3763
3764 // Advanced demonstration of BeginMultiSelect()
3765 // - Showcase clipping.
3766 // - Showcase deletion.
3767 // - Showcase basic drag and drop.
3768 // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
3769 // - Showcase using inside a table.
3770 IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)");
3771 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
3772 if (ImGui::TreeNode("Multi-Select (advanced)"))
3773 {
3774 // Options
3775 enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
3776 static bool use_clipper = true;
3777 static bool use_deletion = true;
3778 static bool use_drag_drop = true;
3779 static bool show_in_table = false;
3780 static bool show_color_button = true;
3781 static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
3782 static WidgetType widget_type = WidgetType_Selectable;
3783
3784 if (ImGui::TreeNode("Options"))
3785 {
3786 if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
3787 ImGui::SameLine();
3788 if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
3789 ImGui::SameLine();
3790 HelpMarker("TreeNode() is technically supported but... using this correctly is more complicated (you need some sort of linear/random access to your tree, which is suited to advanced trees setups already implementing filters and clipper. We will work toward simplifying and demoing this.\n\nFor now the tree demo is actually a little bit meaningless because it is an empty tree with only root nodes.");
3791 ImGui::Checkbox("Enable clipper", &use_clipper);
3792 ImGui::Checkbox("Enable deletion", &use_deletion);
3793 ImGui::Checkbox("Enable drag & drop", &use_drag_drop);
3794 ImGui::Checkbox("Show in a table", &show_in_table);
3795 ImGui::Checkbox("Show color button", &show_color_button);
3796 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect);
3797 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
3798 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect);
3799 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
3800 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
3801 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect);
3802 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
3803 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d);
3804 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll);
3805 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
3806 ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
3807 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
3808 flags &= ~ImGuiMultiSelectFlags_ScopeRect;
3809 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
3810 flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
3811 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick))
3812 flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease;
3813 if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
3814 flags &= ~ImGuiMultiSelectFlags_SelectOnClick;
3815 ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
3816 ImGui::TreePop();
3817 }
3818
3819 // Initialize default list with 1000 items.
3820 // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
3821 static ImVector<int> items;
3822 static int items_next_id = 0;
3823 if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
3824 static ExampleSelectionWithDeletion selection;
3825 static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
3826
3827 ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
3828
3829 const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
3830 ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
3831 if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
3832 {
3833 ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
3834 if (widget_type == WidgetType_TreeNode)
3835 ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
3836
3837 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
3838 selection.ApplyRequests(ms_io);
3839
3840 const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
3841 const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
3842 request_deletion_from_menu = false;
3843
3844 if (show_in_table)
3845 {
3846 if (widget_type == WidgetType_TreeNode)
3847 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
3848 ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX);
3849 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f);
3850 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f);
3851 //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f);
3852 }
3853
3854 ImGuiListClipper clipper;
3855 if (use_clipper)
3856 {
3857 clipper.Begin(items.Size);
3858 if (item_curr_idx_to_focus != -1)
3859 clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
3860 if (ms_io->RangeSrcItem != -1)
3861 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
3862 }
3863
3864 while (!use_clipper || clipper.Step())
3865 {
3866 const int item_begin = use_clipper ? clipper.DisplayStart : 0;
3867 const int item_end = use_clipper ? clipper.DisplayEnd : items.Size;
3868 for (int n = item_begin; n < item_end; n++)
3869 {
3870 if (show_in_table)
3871 ImGui::TableNextColumn();
3872
3873 const int item_id = items[n];
3874 const char* item_category = ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)];
3875 char label[64];
3876 sprintf(label, "Object %05d: %s", item_id, item_category);
3877
3878 // IMPORTANT: for deletion refocus to work we need object ID to be stable,
3879 // aka not depend on their index in the list. Here we use our persistent item_id
3880 // instead of index to build a unique ID that will persist.
3881 // (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
3882 ImGui::PushID(item_id);
3883
3884 // Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
3885 // of the selection scope doesn't erroneously alter our selection.
3886 if (show_color_button)
3887 {
3888 ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
3889 ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz);
3890 ImGui::SameLine();
3891 }
3892
3893 // Submit item
3894 bool item_is_selected = selection.Contains((ImGuiID)n);
3895 bool item_is_open = false;
3896 ImGui::SetNextItemSelectionUserData(n);
3897 if (widget_type == WidgetType_Selectable)
3898 {
3899 ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
3900 }
3901 else if (widget_type == WidgetType_TreeNode)
3902 {
3903 ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
3904 if (item_is_selected)
3905 tree_node_flags |= ImGuiTreeNodeFlags_Selected;
3906 item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
3907 }
3908
3909 // Focus (for after deletion)
3910 if (item_curr_idx_to_focus == n)
3911 ImGui::SetKeyboardFocusHere(-1);
3912
3913 // Drag and Drop
3914 if (use_drag_drop && ImGui::BeginDragDropSource())
3915 {
3916 // Create payload with full selection OR single unselected item.
3917 // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
3918 if (ImGui::GetDragDropPayload() == NULL)
3919 {
3920 ImVector<int> payload_items;
3921 void* it = NULL;
3922 ImGuiID id = 0;
3923 if (!item_is_selected)
3924 payload_items.push_back(item_id);
3925 else
3926 while (selection.GetNextSelectedItem(&it, &id))
3927 payload_items.push_back((int)id);
3928 ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
3929 }
3930
3931 // Display payload content in tooltip
3932 const ImGuiPayload* payload = ImGui::GetDragDropPayload();
3933 const int* payload_items = (int*)payload->Data;
3934 const int payload_count = (int)payload->DataSize / (int)sizeof(int);
3935 if (payload_count == 1)
3936 ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]);
3937 else
3938 ImGui::Text("Dragging %d objects", payload_count);
3939
3940 ImGui::EndDragDropSource();
3941 }
3942
3943 if (widget_type == WidgetType_TreeNode && item_is_open)
3944 ImGui::TreePop();
3945
3946 // Right-click: context menu
3947 if (ImGui::BeginPopupContextItem())
3948 {
3949 ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
3950 sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
3951 if (ImGui::Selectable(label))
3952 request_deletion_from_menu = true;
3953 ImGui::EndDisabled();
3954 ImGui::Selectable("Close");
3955 ImGui::EndPopup();
3956 }
3957
3958 // Demo content within a table
3959 if (show_in_table)
3960 {
3961 ImGui::TableNextColumn();
3962 ImGui::SetNextItemWidth(-FLT_MIN);
3963 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3964 ImGui::InputText("###NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly);
3965 ImGui::PopStyleVar();
3966 }
3967
3968 ImGui::PopID();
3969 }
3970 if (!use_clipper)
3971 break;
3972 }
3973
3974 if (show_in_table)
3975 {
3976 ImGui::EndTable();
3977 if (widget_type == WidgetType_TreeNode)
3978 ImGui::PopStyleVar();
3979 }
3980
3981 // Apply multi-select requests
3982 ms_io = ImGui::EndMultiSelect();
3983 selection.ApplyRequests(ms_io);
3984 if (want_delete)
3985 selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
3986
3987 if (widget_type == WidgetType_TreeNode)
3988 ImGui::PopStyleVar();
3989 }
3990 ImGui::EndChild();
3991 ImGui::TreePop();
3992 }
3993 ImGui::TreePop();
3994 }
3995}
3996
3997//-----------------------------------------------------------------------------
3998// [SECTION] ShowDemoWindowLayout()
3999//-----------------------------------------------------------------------------
4000
4001static void ShowDemoWindowLayout()
4002{
4003 IMGUI_DEMO_MARKER("Layout");
4004 if (!ImGui::CollapsingHeader("Layout & Scrolling"))
4005 return;
4006
4007 IMGUI_DEMO_MARKER("Layout/Child windows");
4008 if (ImGui::TreeNode("Child windows"))
4009 {
4010 ImGui::SeparatorText("Child windows");
4011
4012 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
4013 static bool disable_mouse_wheel = false;
4014 static bool disable_menu = false;
4015 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
4016 ImGui::Checkbox("Disable Menu", &disable_menu);
4017
4018 // Child 1: no border, enable horizontal scrollbar
4019 {
4020 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
4021 if (disable_mouse_wheel)
4022 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4023 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags);
4024 for (int i = 0; i < 100; i++)
4025 ImGui::Text("%04d: scrollable region", i);
4026 ImGui::EndChild();
4027 }
4028
4029 ImGui::SameLine();
4030
4031 // Child 2: rounded border
4032 {
4033 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
4034 if (disable_mouse_wheel)
4035 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
4036 if (!disable_menu)
4037 window_flags |= ImGuiWindowFlags_MenuBar;
4038 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
4039 ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags);
4040 if (!disable_menu && ImGui::BeginMenuBar())
4041 {
4042 if (ImGui::BeginMenu("Menu"))
4043 {
4044 ShowExampleMenuFile();
4045 ImGui::EndMenu();
4046 }
4047 ImGui::EndMenuBar();
4048 }
4049 if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
4050 {
4051 for (int i = 0; i < 100; i++)
4052 {
4053 char buf[32];
4054 sprintf(buf, "%03d", i);
4055 ImGui::TableNextColumn();
4056 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4057 }
4058 ImGui::EndTable();
4059 }
4060 ImGui::EndChild();
4061 ImGui::PopStyleVar();
4062 }
4063
4064 // Child 3: manual-resize
4065 ImGui::SeparatorText("Manual-resize");
4066 {
4067 HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
4068 //if (ImGui::Button("Set Height to 200"))
4069 // ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f));
4070
4071 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
4072 if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
4073 for (int n = 0; n < 10; n++)
4074 ImGui::Text("Line %04d", n);
4075 ImGui::PopStyleColor();
4076 ImGui::EndChild();
4077 }
4078
4079 // Child 4: auto-resizing height with a limit
4080 ImGui::SeparatorText("Auto-resize with constraints");
4081 {
4082 static int draw_lines = 3;
4083 static int max_height_in_lines = 10;
4084 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4085 ImGui::DragInt("Lines Count", &draw_lines, 0.2f);
4086 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4087 ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
4088
4089 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
4090 if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY))
4091 for (int n = 0; n < draw_lines; n++)
4092 ImGui::Text("Line %04d", n);
4093 ImGui::EndChild();
4094 }
4095
4096 ImGui::SeparatorText("Misc/Advanced");
4097
4098 // Demonstrate a few extra things
4099 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
4100 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
4101 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively
4102 // layout from this position.
4103 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
4104 // the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
4105 {
4106 static int offset_x = 0;
4107 static bool override_bg_color = true;
4108 static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
4109 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
4110 ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
4111 ImGui::Checkbox("Override ChildBg color", &override_bg_color);
4112 ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders);
4113 ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
4114 ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
4115 ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
4116 ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle);
4117 ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
4118 if (child_flags & ImGuiChildFlags_FrameStyle)
4119 override_bg_color = false;
4120
4121 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
4122 if (override_bg_color)
4123 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
4124 ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
4125 if (override_bg_color)
4126 ImGui::PopStyleColor();
4127
4128 for (int n = 0; n < 50; n++)
4129 ImGui::Text("Some test %d", n);
4130 ImGui::EndChild();
4131 bool child_is_hovered = ImGui::IsItemHovered();
4132 ImVec2 child_rect_min = ImGui::GetItemRectMin();
4133 ImVec2 child_rect_max = ImGui::GetItemRectMax();
4134 ImGui::Text("Hovered: %d", child_is_hovered);
4135 ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y);
4136 }
4137
4138 ImGui::TreePop();
4139 }
4140
4141 IMGUI_DEMO_MARKER("Layout/Widgets Width");
4142 if (ImGui::TreeNode("Widgets Width"))
4143 {
4144 static float f = 0.0f;
4145 static bool show_indented_items = true;
4146 ImGui::Checkbox("Show indented items", &show_indented_items);
4147
4148 // Use SetNextItemWidth() to set the width of a single upcoming item.
4149 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
4150 // In real code use you'll probably want to choose width values that are proportional to your font size
4151 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
4152
4153 ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
4154 ImGui::SameLine(); HelpMarker("Fixed width.");
4155 ImGui::PushItemWidth(100);
4156 ImGui::DragFloat("float##1b", &f);
4157 if (show_indented_items)
4158 {
4159 ImGui::Indent();
4160 ImGui::DragFloat("float (indented)##1b", &f);
4161 ImGui::Unindent();
4162 }
4163 ImGui::PopItemWidth();
4164
4165 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
4166 ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
4167 ImGui::PushItemWidth(-100);
4168 ImGui::DragFloat("float##2a", &f);
4169 if (show_indented_items)
4170 {
4171 ImGui::Indent();
4172 ImGui::DragFloat("float (indented)##2b", &f);
4173 ImGui::Unindent();
4174 }
4175 ImGui::PopItemWidth();
4176
4177 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
4178 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
4179 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
4180 ImGui::DragFloat("float##3a", &f);
4181 if (show_indented_items)
4182 {
4183 ImGui::Indent();
4184 ImGui::DragFloat("float (indented)##3b", &f);
4185 ImGui::Unindent();
4186 }
4187 ImGui::PopItemWidth();
4188
4189 ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
4190 ImGui::SameLine(); HelpMarker("Align to right edge minus half");
4191 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
4192 ImGui::DragFloat("float##4a", &f);
4193 if (show_indented_items)
4194 {
4195 ImGui::Indent();
4196 ImGui::DragFloat("float (indented)##4b", &f);
4197 ImGui::Unindent();
4198 }
4199 ImGui::PopItemWidth();
4200
4201 // Demonstrate using PushItemWidth to surround three items.
4202 // Calling SetNextItemWidth() before each of them would have the same effect.
4203 ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
4204 ImGui::SameLine(); HelpMarker("Align to right edge");
4205 ImGui::PushItemWidth(-FLT_MIN);
4206 ImGui::DragFloat("##float5a", &f);
4207 if (show_indented_items)
4208 {
4209 ImGui::Indent();
4210 ImGui::DragFloat("float (indented)##5b", &f);
4211 ImGui::Unindent();
4212 }
4213 ImGui::PopItemWidth();
4214
4215 ImGui::TreePop();
4216 }
4217
4218 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
4219 if (ImGui::TreeNode("Basic Horizontal Layout"))
4220 {
4221 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
4222
4223 // Text
4224 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
4225 ImGui::Text("Two items: Hello"); ImGui::SameLine();
4226 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4227
4228 // Adjust spacing
4229 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
4230 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
4231
4232 // Button
4233 ImGui::AlignTextToFramePadding();
4234 ImGui::Text("Normal buttons"); ImGui::SameLine();
4235 ImGui::Button("Banana"); ImGui::SameLine();
4236 ImGui::Button("Apple"); ImGui::SameLine();
4237 ImGui::Button("Corniflower");
4238
4239 // Button
4240 ImGui::Text("Small buttons"); ImGui::SameLine();
4241 ImGui::SmallButton("Like this one"); ImGui::SameLine();
4242 ImGui::Text("can fit within a text block.");
4243
4244 // Aligned to arbitrary position. Easy/cheap column.
4245 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
4246 ImGui::Text("Aligned");
4247 ImGui::SameLine(150); ImGui::Text("x=150");
4248 ImGui::SameLine(300); ImGui::Text("x=300");
4249 ImGui::Text("Aligned");
4250 ImGui::SameLine(150); ImGui::SmallButton("x=150");
4251 ImGui::SameLine(300); ImGui::SmallButton("x=300");
4252
4253 // Checkbox
4254 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
4255 static bool c1 = false, c2 = false, c3 = false, c4 = false;
4256 ImGui::Checkbox("My", &c1); ImGui::SameLine();
4257 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
4258 ImGui::Checkbox("Is", &c3); ImGui::SameLine();
4259 ImGui::Checkbox("Rich", &c4);
4260
4261 // Various
4262 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
4263 ImGui::PushItemWidth(80);
4264 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
4265 static int item = -1;
4266 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
4267 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
4268 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
4269 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
4270 ImGui::PopItemWidth();
4271
4272 ImGui::PushItemWidth(80);
4273 ImGui::Text("Lists:");
4274 static int selection[4] = { 0, 1, 2, 3 };
4275 for (int i = 0; i < 4; i++)
4276 {
4277 if (i > 0) ImGui::SameLine();
4278 ImGui::PushID(i);
4279 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
4280 ImGui::PopID();
4281 //ImGui::SetItemTooltip("ListBox %d hovered", i);
4282 }
4283 ImGui::PopItemWidth();
4284
4285 // Dummy
4286 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
4287 ImVec2 button_sz(40, 40);
4288 ImGui::Button("A", button_sz); ImGui::SameLine();
4289 ImGui::Dummy(button_sz); ImGui::SameLine();
4290 ImGui::Button("B", button_sz);
4291
4292 // Manually wrapping
4293 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
4294 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
4295 ImGui::Text("Manual wrapping:");
4296 ImGuiStyle& style = ImGui::GetStyle();
4297 int buttons_count = 20;
4298 float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
4299 for (int n = 0; n < buttons_count; n++)
4300 {
4301 ImGui::PushID(n);
4302 ImGui::Button("Box", button_sz);
4303 float last_button_x2 = ImGui::GetItemRectMax().x;
4304 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
4305 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
4306 ImGui::SameLine();
4307 ImGui::PopID();
4308 }
4309
4310 ImGui::TreePop();
4311 }
4312
4313 IMGUI_DEMO_MARKER("Layout/Groups");
4314 if (ImGui::TreeNode("Groups"))
4315 {
4316 HelpMarker(
4317 "BeginGroup() basically locks the horizontal position for new line. "
4318 "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
4319 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
4320 ImGui::BeginGroup();
4321 {
4322 ImGui::BeginGroup();
4323 ImGui::Button("AAA");
4324 ImGui::SameLine();
4325 ImGui::Button("BBB");
4326 ImGui::SameLine();
4327 ImGui::BeginGroup();
4328 ImGui::Button("CCC");
4329 ImGui::Button("DDD");
4330 ImGui::EndGroup();
4331 ImGui::SameLine();
4332 ImGui::Button("EEE");
4333 ImGui::EndGroup();
4334 ImGui::SetItemTooltip("First group hovered");
4335 }
4336 // Capture the group size and create widgets using the same size
4337 ImVec2 size = ImGui::GetItemRectSize();
4338 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
4339 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
4340
4341 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4342 ImGui::SameLine();
4343 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
4344 ImGui::EndGroup();
4345 ImGui::SameLine();
4346
4347 ImGui::Button("LEVERAGE\nBUZZWORD", size);
4348 ImGui::SameLine();
4349
4350 if (ImGui::BeginListBox("List", size))
4351 {
4352 ImGui::Selectable("Selected", true);
4353 ImGui::Selectable("Not Selected", false);
4354 ImGui::EndListBox();
4355 }
4356
4357 ImGui::TreePop();
4358 }
4359
4360 IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
4361 if (ImGui::TreeNode("Text Baseline Alignment"))
4362 {
4363 {
4364 ImGui::BulletText("Text baseline:");
4365 ImGui::SameLine(); HelpMarker(
4366 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
4367 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
4368 ImGui::Indent();
4369
4370 ImGui::Text("KO Blahblah"); ImGui::SameLine();
4371 ImGui::Button("Some framed item"); ImGui::SameLine();
4372 HelpMarker("Baseline of button will look misaligned with text..");
4373
4374 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4375 // (because we don't know what's coming after the Text() statement, we need to move the text baseline
4376 // down by FramePadding.y ahead of time)
4377 ImGui::AlignTextToFramePadding();
4378 ImGui::Text("OK Blahblah"); ImGui::SameLine();
4379 ImGui::Button("Some framed item##2"); ImGui::SameLine();
4380 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
4381
4382 // SmallButton() uses the same vertical padding as Text
4383 ImGui::Button("TEST##1"); ImGui::SameLine();
4384 ImGui::Text("TEST"); ImGui::SameLine();
4385 ImGui::SmallButton("TEST##2");
4386
4387 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
4388 ImGui::AlignTextToFramePadding();
4389 ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
4390 ImGui::Button("Item##1"); ImGui::SameLine();
4391 ImGui::Text("Item"); ImGui::SameLine();
4392 ImGui::SmallButton("Item##2"); ImGui::SameLine();
4393 ImGui::Button("Item##3");
4394
4395 ImGui::Unindent();
4396 }
4397
4398 ImGui::Spacing();
4399
4400 {
4401 ImGui::BulletText("Multi-line text:");
4402 ImGui::Indent();
4403 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
4404 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4405 ImGui::Text("Banana");
4406
4407 ImGui::Text("Banana"); ImGui::SameLine();
4408 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4409 ImGui::Text("One\nTwo\nThree");
4410
4411 ImGui::Button("HOP##1"); ImGui::SameLine();
4412 ImGui::Text("Banana"); ImGui::SameLine();
4413 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4414 ImGui::Text("Banana");
4415
4416 ImGui::Button("HOP##2"); ImGui::SameLine();
4417 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
4418 ImGui::Text("Banana");
4419 ImGui::Unindent();
4420 }
4421
4422 ImGui::Spacing();
4423
4424 {
4425 ImGui::BulletText("Misc items:");
4426 ImGui::Indent();
4427
4428 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
4429 ImGui::Button("80x80", ImVec2(80, 80));
4430 ImGui::SameLine();
4431 ImGui::Button("50x50", ImVec2(50, 50));
4432 ImGui::SameLine();
4433 ImGui::Button("Button()");
4434 ImGui::SameLine();
4435 ImGui::SmallButton("SmallButton()");
4436
4437 // Tree
4438 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
4439 ImGui::Button("Button##1");
4440 ImGui::SameLine(0.0f, spacing);
4441 if (ImGui::TreeNode("Node##1"))
4442 {
4443 // Placeholder tree data
4444 for (int i = 0; i < 6; i++)
4445 ImGui::BulletText("Item %d..", i);
4446 ImGui::TreePop();
4447 }
4448
4449 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
4450 // Otherwise you can use SmallButton() (smaller fit).
4451 ImGui::AlignTextToFramePadding();
4452
4453 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
4454 // other contents below the node.
4455 bool node_open = ImGui::TreeNode("Node##2");
4456 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
4457 if (node_open)
4458 {
4459 // Placeholder tree data
4460 for (int i = 0; i < 6; i++)
4461 ImGui::BulletText("Item %d..", i);
4462 ImGui::TreePop();
4463 }
4464
4465 // Bullet
4466 ImGui::Button("Button##3");
4467 ImGui::SameLine(0.0f, spacing);
4468 ImGui::BulletText("Bullet text");
4469
4470 ImGui::AlignTextToFramePadding();
4471 ImGui::BulletText("Node");
4472 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
4473 ImGui::Unindent();
4474 }
4475
4476 ImGui::TreePop();
4477 }
4478
4479 IMGUI_DEMO_MARKER("Layout/Scrolling");
4480 if (ImGui::TreeNode("Scrolling"))
4481 {
4482 // Vertical scroll functions
4483 IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
4484 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
4485
4486 static int track_item = 50;
4487 static bool enable_track = true;
4488 static bool enable_extra_decorations = false;
4489 static float scroll_to_off_px = 0.0f;
4490 static float scroll_to_pos_px = 200.0f;
4491
4492 ImGui::Checkbox("Decoration", &enable_extra_decorations);
4493
4494 ImGui::Checkbox("Track", &enable_track);
4495 ImGui::PushItemWidth(100);
4496 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
4497
4498 bool scroll_to_off = ImGui::Button("Scroll Offset");
4499 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
4500
4501 bool scroll_to_pos = ImGui::Button("Scroll To Pos");
4502 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
4503 ImGui::PopItemWidth();
4504
4505 if (scroll_to_off || scroll_to_pos)
4506 enable_track = false;
4507
4508 ImGuiStyle& style = ImGui::GetStyle();
4509 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
4510 if (child_w < 1.0f)
4511 child_w = 1.0f;
4512 ImGui::PushID("##VerticalScrolling");
4513 for (int i = 0; i < 5; i++)
4514 {
4515 if (i > 0) ImGui::SameLine();
4516 ImGui::BeginGroup();
4517 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
4518 ImGui::TextUnformatted(names[i]);
4519
4520 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
4521 const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4522 const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags);
4523 if (ImGui::BeginMenuBar())
4524 {
4526 ImGui::EndMenuBar();
4527 }
4528 if (scroll_to_off)
4529 ImGui::SetScrollY(scroll_to_off_px);
4530 if (scroll_to_pos)
4531 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
4532 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4533 {
4534 for (int item = 0; item < 100; item++)
4535 {
4536 if (enable_track && item == track_item)
4537 {
4538 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4539 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
4540 }
4541 else
4542 {
4543 ImGui::Text("Item %d", item);
4544 }
4545 }
4546 }
4547 float scroll_y = ImGui::GetScrollY();
4548 float scroll_max_y = ImGui::GetScrollMaxY();
4549 ImGui::EndChild();
4550 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
4551 ImGui::EndGroup();
4552 }
4553 ImGui::PopID();
4554
4555 // Horizontal scroll functions
4556 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
4557 ImGui::Spacing();
4558 HelpMarker(
4559 "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
4560 "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
4561 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
4562 "equivalent SetScrollFromPosY(+1) wouldn't.");
4563 ImGui::PushID("##HorizontalScrolling");
4564 for (int i = 0; i < 5; i++)
4565 {
4566 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
4567 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
4568 ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
4569 bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags);
4570 if (scroll_to_off)
4571 ImGui::SetScrollX(scroll_to_off_px);
4572 if (scroll_to_pos)
4573 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
4574 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
4575 {
4576 for (int item = 0; item < 100; item++)
4577 {
4578 if (item > 0)
4579 ImGui::SameLine();
4580 if (enable_track && item == track_item)
4581 {
4582 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
4583 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
4584 }
4585 else
4586 {
4587 ImGui::Text("Item %d", item);
4588 }
4589 }
4590 }
4591 float scroll_x = ImGui::GetScrollX();
4592 float scroll_max_x = ImGui::GetScrollMaxX();
4593 ImGui::EndChild();
4594 ImGui::SameLine();
4595 const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
4596 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
4597 ImGui::Spacing();
4598 }
4599 ImGui::PopID();
4600
4601 // Miscellaneous Horizontal Scrolling Demo
4602 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
4603 HelpMarker(
4604 "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
4605 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
4606 static int lines = 7;
4607 ImGui::SliderInt("Lines", &lines, 1, 15);
4608 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
4609 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
4610 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
4611 ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
4612 for (int line = 0; line < lines; line++)
4613 {
4614 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
4615 // If you want to create your own time line for a real application you may be better off manipulating
4616 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
4617 // yourself. You may also want to use the lower-level ImDrawList API.
4618 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
4619 for (int n = 0; n < num_buttons; n++)
4620 {
4621 if (n > 0) ImGui::SameLine();
4622 ImGui::PushID(n + line * 1000);
4623 char num_buf[16];
4624 sprintf(num_buf, "%d", n);
4625 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
4626 float hue = n * 0.05f;
4627 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
4628 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
4629 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
4630 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
4631 ImGui::PopStyleColor(3);
4632 ImGui::PopID();
4633 }
4634 }
4635 float scroll_x = ImGui::GetScrollX();
4636 float scroll_max_x = ImGui::GetScrollMaxX();
4637 ImGui::EndChild();
4638 ImGui::PopStyleVar(2);
4639 float scroll_x_delta = 0.0f;
4640 ImGui::SmallButton("<<");
4641 if (ImGui::IsItemActive())
4642 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
4643 ImGui::SameLine();
4644 ImGui::Text("Scroll from code"); ImGui::SameLine();
4645 ImGui::SmallButton(">>");
4646 if (ImGui::IsItemActive())
4647 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
4648 ImGui::SameLine();
4649 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
4650 if (scroll_x_delta != 0.0f)
4651 {
4652 // Demonstrate a trick: you can use Begin to set yourself in the context of another window
4653 // (here we are already out of your child window)
4654 ImGui::BeginChild("scrolling");
4655 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
4656 ImGui::EndChild();
4657 }
4658 ImGui::Spacing();
4659
4660 static bool show_horizontal_contents_size_demo_window = false;
4661 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
4662
4663 if (show_horizontal_contents_size_demo_window)
4664 {
4665 static bool show_h_scrollbar = true;
4666 static bool show_button = true;
4667 static bool show_tree_nodes = true;
4668 static bool show_text_wrapped = false;
4669 static bool show_columns = true;
4670 static bool show_tab_bar = true;
4671 static bool show_child = false;
4672 static bool explicit_content_size = false;
4673 static float contents_size_x = 300.0f;
4674 if (explicit_content_size)
4675 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
4676 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
4677 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
4678 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
4679 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
4680 HelpMarker(
4681 "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
4682 "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
4683 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
4684 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten)
4685 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width
4686 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
4687 ImGui::Checkbox("Columns", &show_columns); // Will use contents size
4688 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size
4689 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size
4690 ImGui::Checkbox("Explicit content size", &explicit_content_size);
4691 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
4692 if (explicit_content_size)
4693 {
4694 ImGui::SameLine();
4695 ImGui::SetNextItemWidth(100);
4696 ImGui::DragFloat("##csx", &contents_size_x);
4697 ImVec2 p = ImGui::GetCursorScreenPos();
4698 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
4699 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
4700 ImGui::Dummy(ImVec2(0, 10));
4701 }
4702 ImGui::PopStyleVar(2);
4703 ImGui::Separator();
4704 if (show_button)
4705 {
4706 ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
4707 }
4708 if (show_tree_nodes)
4709 {
4710 bool open = true;
4711 if (ImGui::TreeNode("this is a tree node"))
4712 {
4713 if (ImGui::TreeNode("another one of those tree node..."))
4714 {
4715 ImGui::Text("Some tree contents");
4716 ImGui::TreePop();
4717 }
4718 ImGui::TreePop();
4719 }
4720 ImGui::CollapsingHeader("CollapsingHeader", &open);
4721 }
4722 if (show_text_wrapped)
4723 {
4724 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
4725 }
4726 if (show_columns)
4727 {
4728 ImGui::Text("Tables:");
4729 if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
4730 {
4731 for (int n = 0; n < 4; n++)
4732 {
4733 ImGui::TableNextColumn();
4734 ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
4735 }
4736 ImGui::EndTable();
4737 }
4738 ImGui::Text("Columns:");
4739 ImGui::Columns(4);
4740 for (int n = 0; n < 4; n++)
4741 {
4742 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
4743 ImGui::NextColumn();
4744 }
4745 ImGui::Columns(1);
4746 }
4747 if (show_tab_bar && ImGui::BeginTabBar("Hello"))
4748 {
4749 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
4750 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
4751 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
4752 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
4753 ImGui::EndTabBar();
4754 }
4755 if (show_child)
4756 {
4757 ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders);
4758 ImGui::EndChild();
4759 }
4760 ImGui::End();
4761 }
4762
4763 ImGui::TreePop();
4764 }
4765
4766 IMGUI_DEMO_MARKER("Layout/Text Clipping");
4767 if (ImGui::TreeNode("Text Clipping"))
4768 {
4769 static ImVec2 size(100.0f, 100.0f);
4770 static ImVec2 offset(30.0f, 30.0f);
4771 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
4772 ImGui::TextWrapped("(Click and drag to scroll)");
4773
4774 HelpMarker(
4775 "(Left) Using ImGui::PushClipRect():\n"
4776 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
4777 "(use this if you want your clipping rectangle to affect interactions)\n\n"
4778 "(Center) Using ImDrawList::PushClipRect():\n"
4779 "Will alter ImDrawList rendering only.\n"
4780 "(use this as a shortcut if you are only using ImDrawList calls)\n\n"
4781 "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
4782 "Will alter only this specific ImDrawList::AddText() rendering.\n"
4783 "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
4784
4785 for (int n = 0; n < 3; n++)
4786 {
4787 if (n > 0)
4788 ImGui::SameLine();
4789
4790 ImGui::PushID(n);
4791 ImGui::InvisibleButton("##canvas", size);
4792 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
4793 {
4794 offset.x += ImGui::GetIO().MouseDelta.x;
4795 offset.y += ImGui::GetIO().MouseDelta.y;
4796 }
4797 ImGui::PopID();
4798 if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
4799 continue;
4800
4801 const ImVec2 p0 = ImGui::GetItemRectMin();
4802 const ImVec2 p1 = ImGui::GetItemRectMax();
4803 const char* text_str = "Line 1 hello\nLine 2 clip me!";
4804 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
4805 ImDrawList* draw_list = ImGui::GetWindowDrawList();
4806 switch (n)
4807 {
4808 case 0:
4809 ImGui::PushClipRect(p0, p1, true);
4810 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4811 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4812 ImGui::PopClipRect();
4813 break;
4814 case 1:
4815 draw_list->PushClipRect(p0, p1, true);
4816 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4817 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
4818 draw_list->PopClipRect();
4819 break;
4820 case 2:
4821 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
4822 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
4823 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
4824 break;
4825 }
4826 }
4827
4828 ImGui::TreePop();
4829 }
4830
4831 IMGUI_DEMO_MARKER("Layout/Overlap Mode");
4832 if (ImGui::TreeNode("Overlap Mode"))
4833 {
4834 static bool enable_allow_overlap = true;
4835
4836 HelpMarker(
4837 "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
4838 "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
4839 "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
4840 ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap);
4841
4842 ImVec2 button1_pos = ImGui::GetCursorScreenPos();
4843 ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
4844 if (enable_allow_overlap)
4845 ImGui::SetNextItemAllowOverlap();
4846 ImGui::Button("Button 1", ImVec2(80, 80));
4847 ImGui::SetCursorScreenPos(button2_pos);
4848 ImGui::Button("Button 2", ImVec2(80, 80));
4849
4850 // This is typically used with width-spanning items.
4851 // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
4852 // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
4853 if (enable_allow_overlap)
4854 ImGui::SetNextItemAllowOverlap();
4855 ImGui::Selectable("Some Selectable", false);
4856 ImGui::SameLine();
4857 ImGui::SmallButton("++");
4858
4859 ImGui::TreePop();
4860 }
4861}
4862
4863//-----------------------------------------------------------------------------
4864// [SECTION] ShowDemoWindowPopups()
4865//-----------------------------------------------------------------------------
4866
4867static void ShowDemoWindowPopups()
4868{
4869 IMGUI_DEMO_MARKER("Popups");
4870 if (!ImGui::CollapsingHeader("Popups & Modal windows"))
4871 return;
4872
4873 // The properties of popups windows are:
4874 // - They block normal mouse hovering detection outside them. (*)
4875 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
4876 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
4877 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
4878 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
4879 // when normally blocked by a popup.
4880 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
4881 // popups at any time.
4882
4883 // Typical use for regular windows:
4884 // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End();
4885 // Typical use for popups:
4886 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
4887
4888 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
4889 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
4890
4891 IMGUI_DEMO_MARKER("Popups/Popups");
4892 if (ImGui::TreeNode("Popups"))
4893 {
4894 ImGui::TextWrapped(
4895 "When a popup is active, it inhibits interacting with windows that are behind the popup. "
4896 "Clicking outside the popup closes it.");
4897
4898 static int selected_fish = -1;
4899 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
4900 static bool toggles[] = { true, false, false, false, false };
4901
4902 // Simple selection popup (if you want to show the current selection inside the Button itself,
4903 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
4904 if (ImGui::Button("Select.."))
4905 ImGui::OpenPopup("my_select_popup");
4906 ImGui::SameLine();
4907 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
4908 if (ImGui::BeginPopup("my_select_popup"))
4909 {
4910 ImGui::SeparatorText("Aquarium");
4911 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4912 if (ImGui::Selectable(names[i]))
4913 selected_fish = i;
4914 ImGui::EndPopup();
4915 }
4916
4917 // Showing a menu with toggles
4918 if (ImGui::Button("Toggle.."))
4919 ImGui::OpenPopup("my_toggle_popup");
4920 if (ImGui::BeginPopup("my_toggle_popup"))
4921 {
4922 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4923 ImGui::MenuItem(names[i], "", &toggles[i]);
4924 if (ImGui::BeginMenu("Sub-menu"))
4925 {
4926 ImGui::MenuItem("Click me");
4927 ImGui::EndMenu();
4928 }
4929
4930 ImGui::Separator();
4931 ImGui::Text("Tooltip here");
4932 ImGui::SetItemTooltip("I am a tooltip over a popup");
4933
4934 if (ImGui::Button("Stacked Popup"))
4935 ImGui::OpenPopup("another popup");
4936 if (ImGui::BeginPopup("another popup"))
4937 {
4938 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
4939 ImGui::MenuItem(names[i], "", &toggles[i]);
4940 if (ImGui::BeginMenu("Sub-menu"))
4941 {
4942 ImGui::MenuItem("Click me");
4943 if (ImGui::Button("Stacked Popup"))
4944 ImGui::OpenPopup("another popup");
4945 if (ImGui::BeginPopup("another popup"))
4946 {
4947 ImGui::Text("I am the last one here.");
4948 ImGui::EndPopup();
4949 }
4950 ImGui::EndMenu();
4951 }
4952 ImGui::EndPopup();
4953 }
4954 ImGui::EndPopup();
4955 }
4956
4957 // Call the more complete ShowExampleMenuFile which we use in various places of this demo
4958 if (ImGui::Button("With a menu.."))
4959 ImGui::OpenPopup("my_file_popup");
4960 if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar))
4961 {
4962 if (ImGui::BeginMenuBar())
4963 {
4964 if (ImGui::BeginMenu("File"))
4965 {
4966 ShowExampleMenuFile();
4967 ImGui::EndMenu();
4968 }
4969 if (ImGui::BeginMenu("Edit"))
4970 {
4971 ImGui::MenuItem("Dummy");
4972 ImGui::EndMenu();
4973 }
4974 ImGui::EndMenuBar();
4975 }
4976 ImGui::Text("Hello from popup!");
4977 ImGui::Button("This is a dummy button..");
4978 ImGui::EndPopup();
4979 }
4980
4981 ImGui::TreePop();
4982 }
4983
4984 IMGUI_DEMO_MARKER("Popups/Context menus");
4985 if (ImGui::TreeNode("Context menus"))
4986 {
4987 HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
4988
4989 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
4990 // if (id == 0)
4991 // id = GetItemID(); // Use last item id
4992 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
4993 // OpenPopup(id);
4994 // return BeginPopup(id);
4995 // For advanced uses you may want to replicate and customize this code.
4996 // See more details in BeginPopupContextItem().
4997
4998 // Example 1
4999 // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
5000 // and BeginPopupContextItem() will use the last item ID as the popup ID.
5001 {
5002 const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
5003 static int selected = -1;
5004 for (int n = 0; n < 5; n++)
5005 {
5006 if (ImGui::Selectable(names[n], selected == n))
5007 selected = n;
5008 if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
5009 {
5010 selected = n;
5011 ImGui::Text("This a popup for \"%s\"!", names[n]);
5012 if (ImGui::Button("Close"))
5013 ImGui::CloseCurrentPopup();
5014 ImGui::EndPopup();
5015 }
5016 ImGui::SetItemTooltip("Right-click to open popup");
5017 }
5018 }
5019
5020 // Example 2
5021 // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
5022 // Using an explicit identifier is also convenient if you want to activate the popups from different locations.
5023 {
5024 HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
5025 static float value = 0.5f;
5026 ImGui::Text("Value = %.3f <-- (1) right-click this text", value);
5027 if (ImGui::BeginPopupContextItem("my popup"))
5028 {
5029 if (ImGui::Selectable("Set to zero")) value = 0.0f;
5030 if (ImGui::Selectable("Set to PI")) value = 3.1415f;
5031 ImGui::SetNextItemWidth(-FLT_MIN);
5032 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
5033 ImGui::EndPopup();
5034 }
5035
5036 // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
5037 // Here we make it that right-clicking this other text element opens the same popup as above.
5038 // The popup itself will be submitted by the code above.
5039 ImGui::Text("(2) Or right-click this text");
5040 ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
5041
5042 // Back to square one: manually open the same popup.
5043 if (ImGui::Button("(3) Or click this button"))
5044 ImGui::OpenPopup("my popup");
5045 }
5046
5047 // Example 3
5048 // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
5049 // we need to make sure your item identifier is stable.
5050 // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
5051 {
5052 HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
5053 static char name[32] = "Label1";
5054 char buf[64];
5055 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
5056 ImGui::Button(buf);
5057 if (ImGui::BeginPopupContextItem())
5058 {
5059 ImGui::Text("Edit name:");
5060 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
5061 if (ImGui::Button("Close"))
5062 ImGui::CloseCurrentPopup();
5063 ImGui::EndPopup();
5064 }
5065 ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
5066 }
5067
5068 ImGui::TreePop();
5069 }
5070
5071 IMGUI_DEMO_MARKER("Popups/Modals");
5072 if (ImGui::TreeNode("Modals"))
5073 {
5074 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
5075
5076 if (ImGui::Button("Delete.."))
5077 ImGui::OpenPopup("Delete?");
5078
5079 // Always center this window when appearing
5080 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
5081 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
5082
5083 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
5084 {
5085 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
5086 ImGui::Separator();
5087
5088 //static int unused_i = 0;
5089 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
5090
5091 static bool dont_ask_me_next_time = false;
5092 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
5093 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
5094 ImGui::PopStyleVar();
5095
5096 if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5097 ImGui::SetItemDefaultFocus();
5098 ImGui::SameLine();
5099 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
5100 ImGui::EndPopup();
5101 }
5102
5103 if (ImGui::Button("Stacked modals.."))
5104 ImGui::OpenPopup("Stacked 1");
5105 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
5106 {
5107 if (ImGui::BeginMenuBar())
5108 {
5109 if (ImGui::BeginMenu("File"))
5110 {
5111 if (ImGui::MenuItem("Some menu item")) {}
5112 ImGui::EndMenu();
5113 }
5114 ImGui::EndMenuBar();
5115 }
5116 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
5117
5118 // Testing behavior of widgets stacking their own regular popups over the modal.
5119 static int item = 1;
5120 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
5121 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
5122 ImGui::ColorEdit4("Color", color);
5123
5124 if (ImGui::Button("Add another modal.."))
5125 ImGui::OpenPopup("Stacked 2");
5126
5127 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
5128 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
5129 // of the bool actually doesn't matter here.
5130 bool unused_open = true;
5131 if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
5132 {
5133 ImGui::Text("Hello from Stacked The Second!");
5134 ImGui::ColorEdit4("Color", color); // Allow opening another nested popup
5135 if (ImGui::Button("Close"))
5136 ImGui::CloseCurrentPopup();
5137 ImGui::EndPopup();
5138 }
5139
5140 if (ImGui::Button("Close"))
5141 ImGui::CloseCurrentPopup();
5142 ImGui::EndPopup();
5143 }
5144
5145 ImGui::TreePop();
5146 }
5147
5148 IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
5149 if (ImGui::TreeNode("Menus inside a regular window"))
5150 {
5151 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
5152 ImGui::Separator();
5153
5154 ImGui::MenuItem("Menu item", "CTRL+M");
5155 if (ImGui::BeginMenu("Menu inside a regular window"))
5156 {
5157 ShowExampleMenuFile();
5158 ImGui::EndMenu();
5159 }
5160 ImGui::Separator();
5161 ImGui::TreePop();
5162 }
5163}
5164
5165// Dummy data structure that we use for the Table demo.
5166// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
5167namespace
5168{
5169// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
5170// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
5171// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
5172// If you don't use sorting, you will generally never care about giving column an ID!
5173enum MyItemColumnID
5174{
5175 MyItemColumnID_ID,
5176 MyItemColumnID_Name,
5177 MyItemColumnID_Action,
5178 MyItemColumnID_Quantity,
5179 MyItemColumnID_Description
5180};
5181
5182struct MyItem
5183{
5184 int ID;
5185 const char* Name;
5186 int Quantity;
5187
5188 // We have a problem which is affecting _only this demo_ and should not affect your code:
5189 // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
5190 // however qsort doesn't allow passing user data to comparing function.
5191 // As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
5192 // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
5193 // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
5194 // very often by the sorting algorithm it would be a little wasteful.
5195 static const ImGuiTableSortSpecs* s_current_sort_specs;
5196
5197 static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
5198 {
5199 s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
5200 if (items_count > 1)
5201 qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
5202 s_current_sort_specs = NULL;
5203 }
5204
5205 // Compare function to be used by qsort()
5206 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
5207 {
5208 const MyItem* a = (const MyItem*)lhs;
5209 const MyItem* b = (const MyItem*)rhs;
5210 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
5211 {
5212 // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
5213 // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
5214 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
5215 int delta = 0;
5216 switch (sort_spec->ColumnUserID)
5217 {
5218 case MyItemColumnID_ID: delta = (a->ID - b->ID); break;
5219 case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break;
5220 case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break;
5221 case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break;
5222 default: IM_ASSERT(0); break;
5223 }
5224 if (delta > 0)
5225 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
5226 if (delta < 0)
5227 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
5228 }
5229
5230 // qsort() is instable so always return a way to differenciate items.
5231 // Your own compare function may want to avoid fallback on implicit sort specs.
5232 // e.g. a Name compare if it wasn't already part of the sort specs.
5233 return (a->ID - b->ID);
5234 }
5235};
5236const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
5237}
5238
5239// Make the UI compact because there are so many fields
5240static void PushStyleCompact()
5241{
5242 ImGuiStyle& style = ImGui::GetStyle();
5243 ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f));
5244 ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f));
5245}
5246
5247static void PopStyleCompact()
5248{
5249 ImGui::PopStyleVar(2);
5250}
5251
5252// Show a combo box with a choice of sizing policies
5253static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
5254{
5255 struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
5256 static const EnumDesc policies[] =
5257 {
5258 { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." },
5259 { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
5260 { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
5261 { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
5262 { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
5263 };
5264 int idx;
5265 for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
5266 if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
5267 break;
5268 const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
5269 if (ImGui::BeginCombo("Sizing Policy", preview_text))
5270 {
5271 for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
5272 if (ImGui::Selectable(policies[n].Name, idx == n))
5273 *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
5274 ImGui::EndCombo();
5275 }
5276 ImGui::SameLine();
5277 ImGui::TextDisabled("(?)");
5278 if (ImGui::BeginItemTooltip())
5279 {
5280 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
5281 for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
5282 {
5283 ImGui::Separator();
5284 ImGui::Text("%s:", policies[m].Name);
5285 ImGui::Separator();
5286 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
5287 ImGui::TextUnformatted(policies[m].Tooltip);
5288 }
5289 ImGui::PopTextWrapPos();
5290 ImGui::EndTooltip();
5291 }
5292}
5293
5294static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
5295{
5296 ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
5297 ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
5298 ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
5299 if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
5300 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
5301 if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
5302 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
5303 ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
5304 ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
5305 ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
5306 ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
5307 ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
5308 ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
5309 ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
5310 ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
5311 ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
5312 ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
5313 ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
5314 ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
5315 ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
5316 ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
5317}
5318
5319static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
5320{
5321 ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
5322 ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
5323 ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
5324 ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
5325}
5326
5327//-----------------------------------------------------------------------------
5328// [SECTION] ShowDemoWindowTables()
5329//-----------------------------------------------------------------------------
5330
5331static void ShowDemoWindowTables()
5332{
5333 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
5334 IMGUI_DEMO_MARKER("Tables");
5335 if (!ImGui::CollapsingHeader("Tables & Columns"))
5336 return;
5337
5338 // Using those as a base value to create width/height that are factor of the size of our font
5339 const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
5340 const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
5341
5342 ImGui::PushID("Tables");
5343
5344 int open_action = -1;
5345 if (ImGui::Button("Expand all"))
5346 open_action = 1;
5347 ImGui::SameLine();
5348 if (ImGui::Button("Collapse all"))
5349 open_action = 0;
5350 ImGui::SameLine();
5351
5352 // Options
5353 static bool disable_indent = false;
5354 ImGui::Checkbox("Disable tree indentation", &disable_indent);
5355 ImGui::SameLine();
5356 HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
5357 ImGui::Separator();
5358 if (disable_indent)
5359 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
5360
5361 // About Styling of tables
5362 // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
5363 // There are however a few settings that a shared and part of the ImGuiStyle structure:
5364 // style.CellPadding // Padding within each cell
5365 // style.Colors[ImGuiCol_TableHeaderBg] // Table header background
5366 // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders
5367 // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders
5368 // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
5369 // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
5370
5371 // Demos
5372 if (open_action != -1)
5373 ImGui::SetNextItemOpen(open_action != 0);
5374 IMGUI_DEMO_MARKER("Tables/Basic");
5375 if (ImGui::TreeNode("Basic"))
5376 {
5377 // Here we will showcase three different ways to output a table.
5378 // They are very simple variations of a same thing!
5379
5380 // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
5381 // In many situations, this is the most flexible and easy to use pattern.
5382 HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
5383 if (ImGui::BeginTable("table1", 3))
5384 {
5385 for (int row = 0; row < 4; row++)
5386 {
5387 ImGui::TableNextRow();
5388 for (int column = 0; column < 3; column++)
5389 {
5390 ImGui::TableSetColumnIndex(column);
5391 ImGui::Text("Row %d Column %d", row, column);
5392 }
5393 }
5394 ImGui::EndTable();
5395 }
5396
5397 // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
5398 // This is generally more convenient when you have code manually submitting the contents of each column.
5399 HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
5400 if (ImGui::BeginTable("table2", 3))
5401 {
5402 for (int row = 0; row < 4; row++)
5403 {
5404 ImGui::TableNextRow();
5405 ImGui::TableNextColumn();
5406 ImGui::Text("Row %d", row);
5407 ImGui::TableNextColumn();
5408 ImGui::Text("Some contents");
5409 ImGui::TableNextColumn();
5410 ImGui::Text("123.456");
5411 }
5412 ImGui::EndTable();
5413 }
5414
5415 // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
5416 // as TableNextColumn() will automatically wrap around and create new rows as needed.
5417 // This is generally more convenient when your cells all contains the same type of data.
5418 HelpMarker(
5419 "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
5420 "the same type of contents.\n This is also more similar to the old NextColumn() function of the "
5421 "Columns API, and provided to facilitate the Columns->Tables API transition.");
5422 if (ImGui::BeginTable("table3", 3))
5423 {
5424 for (int item = 0; item < 14; item++)
5425 {
5426 ImGui::TableNextColumn();
5427 ImGui::Text("Item %d", item);
5428 }
5429 ImGui::EndTable();
5430 }
5431
5432 ImGui::TreePop();
5433 }
5434
5435 if (open_action != -1)
5436 ImGui::SetNextItemOpen(open_action != 0);
5437 IMGUI_DEMO_MARKER("Tables/Borders, background");
5438 if (ImGui::TreeNode("Borders, background"))
5439 {
5440 // Expose a few Borders related flags interactively
5441 enum ContentsType { CT_Text, CT_FillButton };
5442 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5443 static bool display_headers = false;
5444 static int contents_type = CT_Text;
5445
5446 PushStyleCompact();
5447 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5448 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
5449 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH");
5450 ImGui::Indent();
5451
5452 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
5453 ImGui::Indent();
5454 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
5455 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
5456 ImGui::Unindent();
5457
5458 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5459 ImGui::Indent();
5460 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
5461 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
5462 ImGui::Unindent();
5463
5464 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
5465 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
5466 ImGui::Unindent();
5467
5468 ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
5469 ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
5470 ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
5471 ImGui::Checkbox("Display headers", &display_headers);
5472 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
5473 PopStyleCompact();
5474
5475 if (ImGui::BeginTable("table1", 3, flags))
5476 {
5477 // Display headers so we can inspect their interaction with borders
5478 // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them now. See other sections for details)
5479 if (display_headers)
5480 {
5481 ImGui::TableSetupColumn("One");
5482 ImGui::TableSetupColumn("Two");
5483 ImGui::TableSetupColumn("Three");
5484 ImGui::TableHeadersRow();
5485 }
5486
5487 for (int row = 0; row < 5; row++)
5488 {
5489 ImGui::TableNextRow();
5490 for (int column = 0; column < 3; column++)
5491 {
5492 ImGui::TableSetColumnIndex(column);
5493 char buf[32];
5494 sprintf(buf, "Hello %d,%d", column, row);
5495 if (contents_type == CT_Text)
5497 else if (contents_type == CT_FillButton)
5498 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5499 }
5500 }
5501 ImGui::EndTable();
5502 }
5503 ImGui::TreePop();
5504 }
5505
5506 if (open_action != -1)
5507 ImGui::SetNextItemOpen(open_action != 0);
5508 IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
5509 if (ImGui::TreeNode("Resizable, stretch"))
5510 {
5511 // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
5512 // All columns maintain a sizing weight, and they will occupy all available width.
5513 static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5514 PushStyleCompact();
5515 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5516 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5517 ImGui::SameLine(); HelpMarker(
5518 "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
5519 "this is why the resize borders are still showing when unchecking this.");
5520 PopStyleCompact();
5521
5522 if (ImGui::BeginTable("table1", 3, flags))
5523 {
5524 for (int row = 0; row < 5; row++)
5525 {
5526 ImGui::TableNextRow();
5527 for (int column = 0; column < 3; column++)
5528 {
5529 ImGui::TableSetColumnIndex(column);
5530 ImGui::Text("Hello %d,%d", column, row);
5531 }
5532 }
5533 ImGui::EndTable();
5534 }
5535 ImGui::TreePop();
5536 }
5537
5538 if (open_action != -1)
5539 ImGui::SetNextItemOpen(open_action != 0);
5540 IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
5541 if (ImGui::TreeNode("Resizable, fixed"))
5542 {
5543 // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
5544 // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
5545 // If there is not enough available width to fit all columns, they will however be resized down.
5546 // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
5547 HelpMarker(
5548 "Using _Resizable + _SizingFixedFit flags.\n"
5549 "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
5550 "Double-click a column border to auto-fit the column to its contents.");
5551 PushStyleCompact();
5552 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
5553 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5554 PopStyleCompact();
5555
5556 if (ImGui::BeginTable("table1", 3, flags))
5557 {
5558 for (int row = 0; row < 5; row++)
5559 {
5560 ImGui::TableNextRow();
5561 for (int column = 0; column < 3; column++)
5562 {
5563 ImGui::TableSetColumnIndex(column);
5564 ImGui::Text("Hello %d,%d", column, row);
5565 }
5566 }
5567 ImGui::EndTable();
5568 }
5569 ImGui::TreePop();
5570 }
5571
5572 if (open_action != -1)
5573 ImGui::SetNextItemOpen(open_action != 0);
5574 IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
5575 if (ImGui::TreeNode("Resizable, mixed"))
5576 {
5577 HelpMarker(
5578 "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
5579 "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
5580 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5581
5582 if (ImGui::BeginTable("table1", 3, flags))
5583 {
5584 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5585 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5586 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
5587 ImGui::TableHeadersRow();
5588 for (int row = 0; row < 5; row++)
5589 {
5590 ImGui::TableNextRow();
5591 for (int column = 0; column < 3; column++)
5592 {
5593 ImGui::TableSetColumnIndex(column);
5594 ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
5595 }
5596 }
5597 ImGui::EndTable();
5598 }
5599 if (ImGui::BeginTable("table2", 6, flags))
5600 {
5601 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
5602 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
5603 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
5604 ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
5605 ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
5606 ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
5607 ImGui::TableHeadersRow();
5608 for (int row = 0; row < 5; row++)
5609 {
5610 ImGui::TableNextRow();
5611 for (int column = 0; column < 6; column++)
5612 {
5613 ImGui::TableSetColumnIndex(column);
5614 ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
5615 }
5616 }
5617 ImGui::EndTable();
5618 }
5619 ImGui::TreePop();
5620 }
5621
5622 if (open_action != -1)
5623 ImGui::SetNextItemOpen(open_action != 0);
5624 IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
5625 if (ImGui::TreeNode("Reorderable, hideable, with headers"))
5626 {
5627 HelpMarker(
5628 "Click and drag column headers to reorder columns.\n\n"
5629 "Right-click on a header to open a context menu.");
5630 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
5631 PushStyleCompact();
5632 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5633 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
5634 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
5635 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
5636 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
5637 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5638 PopStyleCompact();
5639
5640 if (ImGui::BeginTable("table1", 3, flags))
5641 {
5642 // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
5643 // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
5644 ImGui::TableSetupColumn("One");
5645 ImGui::TableSetupColumn("Two");
5646 ImGui::TableSetupColumn("Three");
5647 ImGui::TableHeadersRow();
5648 for (int row = 0; row < 6; row++)
5649 {
5650 ImGui::TableNextRow();
5651 for (int column = 0; column < 3; column++)
5652 {
5653 ImGui::TableSetColumnIndex(column);
5654 ImGui::Text("Hello %d,%d", column, row);
5655 }
5656 }
5657 ImGui::EndTable();
5658 }
5659
5660 // Use outer_size.x == 0.0f instead of default to make the table as tight as possible
5661 // (only valid when no scrolling and no stretch column)
5662 if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
5663 {
5664 ImGui::TableSetupColumn("One");
5665 ImGui::TableSetupColumn("Two");
5666 ImGui::TableSetupColumn("Three");
5667 ImGui::TableHeadersRow();
5668 for (int row = 0; row < 6; row++)
5669 {
5670 ImGui::TableNextRow();
5671 for (int column = 0; column < 3; column++)
5672 {
5673 ImGui::TableSetColumnIndex(column);
5674 ImGui::Text("Fixed %d,%d", column, row);
5675 }
5676 }
5677 ImGui::EndTable();
5678 }
5679 ImGui::TreePop();
5680 }
5681
5682 if (open_action != -1)
5683 ImGui::SetNextItemOpen(open_action != 0);
5684 IMGUI_DEMO_MARKER("Tables/Padding");
5685 if (ImGui::TreeNode("Padding"))
5686 {
5687 // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
5688 // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
5689 HelpMarker(
5690 "We often want outer padding activated when any using features which makes the edges of a column visible:\n"
5691 "e.g.:\n"
5692 "- BorderOuterV\n"
5693 "- any form of row selection\n"
5694 "Because of this, activating BorderOuterV sets the default to PadOuterX. "
5695 "Using PadOuterX or NoPadOuterX you can override the default.\n\n"
5696 "Actual padding values are using style.CellPadding.\n\n"
5697 "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
5698
5699 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
5700 PushStyleCompact();
5701 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
5702 ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
5703 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
5704 ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
5705 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
5706 ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
5707 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
5708 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
5709 static bool show_headers = false;
5710 ImGui::Checkbox("show_headers", &show_headers);
5711 PopStyleCompact();
5712
5713 if (ImGui::BeginTable("table_padding", 3, flags1))
5714 {
5715 if (show_headers)
5716 {
5717 ImGui::TableSetupColumn("One");
5718 ImGui::TableSetupColumn("Two");
5719 ImGui::TableSetupColumn("Three");
5720 ImGui::TableHeadersRow();
5721 }
5722
5723 for (int row = 0; row < 5; row++)
5724 {
5725 ImGui::TableNextRow();
5726 for (int column = 0; column < 3; column++)
5727 {
5728 ImGui::TableSetColumnIndex(column);
5729 if (row == 0)
5730 {
5731 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
5732 }
5733 else
5734 {
5735 char buf[32];
5736 sprintf(buf, "Hello %d,%d", column, row);
5737 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
5738 }
5739 //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
5740 // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
5741 }
5742 }
5743 ImGui::EndTable();
5744 }
5745
5746 // Second example: set style.CellPadding to (0.0) or a custom value.
5747 // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
5748 HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
5749 static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
5750 static ImVec2 cell_padding(0.0f, 0.0f);
5751 static bool show_widget_frame_bg = true;
5752
5753 PushStyleCompact();
5754 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
5755 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
5756 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
5757 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
5758 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
5759 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
5760 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
5761 ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
5762 ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
5763 PopStyleCompact();
5764
5765 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
5766 if (ImGui::BeginTable("table_padding_2", 3, flags2))
5767 {
5768 static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
5769 static bool init = true;
5770 if (!show_widget_frame_bg)
5771 ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
5772 for (int cell = 0; cell < 3 * 5; cell++)
5773 {
5774 ImGui::TableNextColumn();
5775 if (init)
5776 strcpy(text_bufs[cell], "edit me");
5777 ImGui::SetNextItemWidth(-FLT_MIN);
5778 ImGui::PushID(cell);
5779 ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
5780 ImGui::PopID();
5781 }
5782 if (!show_widget_frame_bg)
5783 ImGui::PopStyleColor();
5784 init = false;
5785 ImGui::EndTable();
5786 }
5787 ImGui::PopStyleVar();
5788
5789 ImGui::TreePop();
5790 }
5791
5792 if (open_action != -1)
5793 ImGui::SetNextItemOpen(open_action != 0);
5794 IMGUI_DEMO_MARKER("Tables/Explicit widths");
5795 if (ImGui::TreeNode("Sizing policies"))
5796 {
5797 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
5798 PushStyleCompact();
5799 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
5800 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
5801 PopStyleCompact();
5802
5803 static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
5804 for (int table_n = 0; table_n < 4; table_n++)
5805 {
5806 ImGui::PushID(table_n);
5807 ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
5808 EditTableSizingFlags(&sizing_policy_flags[table_n]);
5809
5810 // To make it easier to understand the different sizing policy,
5811 // For each policy: we display one table where the columns have equal contents width,
5812 // and one where the columns have different contents width.
5813 if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
5814 {
5815 for (int row = 0; row < 3; row++)
5816 {
5817 ImGui::TableNextRow();
5818 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5819 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5820 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
5821 }
5822 ImGui::EndTable();
5823 }
5824 if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
5825 {
5826 for (int row = 0; row < 3; row++)
5827 {
5828 ImGui::TableNextRow();
5829 ImGui::TableNextColumn(); ImGui::Text("AAAA");
5830 ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
5831 ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
5832 }
5833 ImGui::EndTable();
5834 }
5835 ImGui::PopID();
5836 }
5837
5838 ImGui::Spacing();
5839 ImGui::TextUnformatted("Advanced");
5840 ImGui::SameLine();
5841 HelpMarker(
5842 "This section allows you to interact and see the effect of various sizing policies "
5843 "depending on whether Scroll is enabled and the contents of your columns.");
5844
5845 enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
5846 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
5847 static int contents_type = CT_ShowWidth;
5848 static int column_count = 3;
5849
5850 PushStyleCompact();
5851 ImGui::PushID("Advanced");
5852 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
5853 EditTableSizingFlags(&flags);
5854 ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
5855 if (contents_type == CT_FillButton)
5856 {
5857 ImGui::SameLine();
5858 HelpMarker(
5859 "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
5860 "where contents width can feed into auto-column width can feed into contents width.");
5861 }
5862 ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
5863 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5864 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
5865 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
5866 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5867 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5868 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
5869 ImGui::PopItemWidth();
5870 ImGui::PopID();
5871 PopStyleCompact();
5872
5873 if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
5874 {
5875 for (int cell = 0; cell < 10 * column_count; cell++)
5876 {
5877 ImGui::TableNextColumn();
5878 int column = ImGui::TableGetColumnIndex();
5879 int row = ImGui::TableGetRowIndex();
5880
5881 ImGui::PushID(cell);
5882 char label[32];
5883 static char text_buf[32] = "";
5884 sprintf(label, "Hello %d,%d", column, row);
5885 switch (contents_type)
5886 {
5887 case CT_ShortText: ImGui::TextUnformatted(label); break;
5888 case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
5889 case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
5890 case CT_Button: ImGui::Button(label); break;
5891 case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
5892 case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
5893 }
5894 ImGui::PopID();
5895 }
5896 ImGui::EndTable();
5897 }
5898 ImGui::TreePop();
5899 }
5900
5901 if (open_action != -1)
5902 ImGui::SetNextItemOpen(open_action != 0);
5903 IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
5904 if (ImGui::TreeNode("Vertical scrolling, with clipping"))
5905 {
5906 HelpMarker(
5907 "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
5908 "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
5909 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5910
5911 PushStyleCompact();
5912 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5913 PopStyleCompact();
5914
5915 // When using ScrollX or ScrollY we need to specify a size for our table container!
5916 // Otherwise by default the table will fit all available space, like a BeginChild() call.
5917 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5918 if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
5919 {
5920 ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
5921 ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
5922 ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
5923 ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
5924 ImGui::TableHeadersRow();
5925
5926 // Demonstrate using clipper for large vertical lists
5927 ImGuiListClipper clipper;
5928 clipper.Begin(1000);
5929 while (clipper.Step())
5930 {
5931 for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
5932 {
5933 ImGui::TableNextRow();
5934 for (int column = 0; column < 3; column++)
5935 {
5936 ImGui::TableSetColumnIndex(column);
5937 ImGui::Text("Hello %d,%d", column, row);
5938 }
5939 }
5940 }
5941 ImGui::EndTable();
5942 }
5943 ImGui::TreePop();
5944 }
5945
5946 if (open_action != -1)
5947 ImGui::SetNextItemOpen(open_action != 0);
5948 IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
5949 if (ImGui::TreeNode("Horizontal scrolling"))
5950 {
5951 HelpMarker(
5952 "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
5953 "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
5954 "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
5955 "because the container window won't automatically extend vertically to fix contents "
5956 "(this may be improved in future versions).");
5957 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
5958 static int freeze_cols = 1;
5959 static int freeze_rows = 1;
5960
5961 PushStyleCompact();
5962 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5963 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5964 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5965 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5966 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5967 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5968 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5969 PopStyleCompact();
5970
5971 // When using ScrollX or ScrollY we need to specify a size for our table container!
5972 // Otherwise by default the table will fit all available space, like a BeginChild() call.
5973 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
5974 if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
5975 {
5976 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
5977 ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
5978 ImGui::TableSetupColumn("One");
5979 ImGui::TableSetupColumn("Two");
5980 ImGui::TableSetupColumn("Three");
5981 ImGui::TableSetupColumn("Four");
5982 ImGui::TableSetupColumn("Five");
5983 ImGui::TableSetupColumn("Six");
5984 ImGui::TableHeadersRow();
5985 for (int row = 0; row < 20; row++)
5986 {
5987 ImGui::TableNextRow();
5988 for (int column = 0; column < 7; column++)
5989 {
5990 // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
5991 // Because here we know that:
5992 // - A) all our columns are contributing the same to row height
5993 // - B) column 0 is always visible,
5994 // We only always submit this one column and can skip others.
5995 // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
5996 if (!ImGui::TableSetColumnIndex(column) && column > 0)
5997 continue;
5998 if (column == 0)
5999 ImGui::Text("Line %d", row);
6000 else
6001 ImGui::Text("Hello world %d,%d", column, row);
6002 }
6003 }
6004 ImGui::EndTable();
6005 }
6006
6007 ImGui::Spacing();
6008 ImGui::TextUnformatted("Stretch + ScrollX");
6009 ImGui::SameLine();
6010 HelpMarker(
6011 "Showcase using Stretch columns + ScrollX together: "
6012 "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
6013 "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
6014 "along with ScrollX doesn't make sense.");
6015 static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
6016 static float inner_width = 1000.0f;
6017 PushStyleCompact();
6018 ImGui::PushID("flags3");
6019 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
6020 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
6021 ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
6022 ImGui::PopItemWidth();
6023 ImGui::PopID();
6024 PopStyleCompact();
6025 if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
6026 {
6027 for (int cell = 0; cell < 20 * 7; cell++)
6028 {
6029 ImGui::TableNextColumn();
6030 ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
6031 }
6032 ImGui::EndTable();
6033 }
6034 ImGui::TreePop();
6035 }
6036
6037 if (open_action != -1)
6038 ImGui::SetNextItemOpen(open_action != 0);
6039 IMGUI_DEMO_MARKER("Tables/Columns flags");
6040 if (ImGui::TreeNode("Columns flags"))
6041 {
6042 // Create a first table just to show all the options/flags we want to make visible in our example!
6043 const int column_count = 3;
6044 const char* column_names[column_count] = { "One", "Two", "Three" };
6045 static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
6046 static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
6047
6048 if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
6049 {
6050 PushStyleCompact();
6051 for (int column = 0; column < column_count; column++)
6052 {
6053 ImGui::TableNextColumn();
6054 ImGui::PushID(column);
6055 ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
6056 ImGui::Text("'%s'", column_names[column]);
6057 ImGui::Spacing();
6058 ImGui::Text("Input flags:");
6059 EditTableColumnsFlags(&column_flags[column]);
6060 ImGui::Spacing();
6061 ImGui::Text("Output flags:");
6062 ImGui::BeginDisabled();
6063 ShowTableColumnsStatusFlags(column_flags_out[column]);
6064 ImGui::EndDisabled();
6065 ImGui::PopID();
6066 }
6067 PopStyleCompact();
6068 ImGui::EndTable();
6069 }
6070
6071 // Create the real table we care about for the example!
6072 // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
6073 // otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
6074 // + resizing the parent window down).
6075 const ImGuiTableFlags flags
6076 = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6077 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
6078 | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
6079 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
6080 if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
6081 {
6082 bool has_angled_header = false;
6083 for (int column = 0; column < column_count; column++)
6084 {
6085 has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
6086 ImGui::TableSetupColumn(column_names[column], column_flags[column]);
6087 }
6088 if (has_angled_header)
6089 ImGui::TableAngledHeadersRow();
6090 ImGui::TableHeadersRow();
6091 for (int column = 0; column < column_count; column++)
6092 column_flags_out[column] = ImGui::TableGetColumnFlags(column);
6093 float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
6094 for (int row = 0; row < 8; row++)
6095 {
6096 // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
6097 ImGui::Indent(indent_step);
6098 ImGui::TableNextRow();
6099 for (int column = 0; column < column_count; column++)
6100 {
6101 ImGui::TableSetColumnIndex(column);
6102 ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
6103 }
6104 }
6105 ImGui::Unindent(indent_step * 8.0f);
6106
6107 ImGui::EndTable();
6108 }
6109 ImGui::TreePop();
6110 }
6111
6112 if (open_action != -1)
6113 ImGui::SetNextItemOpen(open_action != 0);
6114 IMGUI_DEMO_MARKER("Tables/Columns widths");
6115 if (ImGui::TreeNode("Columns widths"))
6116 {
6117 HelpMarker("Using TableSetupColumn() to setup default width.");
6118
6119 static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
6120 PushStyleCompact();
6121 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
6122 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
6123 PopStyleCompact();
6124 if (ImGui::BeginTable("table1", 3, flags1))
6125 {
6126 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
6127 ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
6128 ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
6129 ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto
6130 ImGui::TableHeadersRow();
6131 for (int row = 0; row < 4; row++)
6132 {
6133 ImGui::TableNextRow();
6134 for (int column = 0; column < 3; column++)
6135 {
6136 ImGui::TableSetColumnIndex(column);
6137 if (row == 0)
6138 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6139 else
6140 ImGui::Text("Hello %d,%d", column, row);
6141 }
6142 }
6143 ImGui::EndTable();
6144 }
6145
6146 HelpMarker(
6147 "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
6148 "fixed columns with set width may still be shrunk down if there's not enough space in the host.");
6149
6150 static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
6151 PushStyleCompact();
6152 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
6153 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
6154 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
6155 PopStyleCompact();
6156 if (ImGui::BeginTable("table2", 4, flags2))
6157 {
6158 // We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
6159 // will default to ImGuiTableColumnFlags_WidthFixed.
6160 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
6161 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6162 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
6163 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
6164 for (int row = 0; row < 5; row++)
6165 {
6166 ImGui::TableNextRow();
6167 for (int column = 0; column < 4; column++)
6168 {
6169 ImGui::TableSetColumnIndex(column);
6170 if (row == 0)
6171 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
6172 else
6173 ImGui::Text("Hello %d,%d", column, row);
6174 }
6175 }
6176 ImGui::EndTable();
6177 }
6178 ImGui::TreePop();
6179 }
6180
6181 if (open_action != -1)
6182 ImGui::SetNextItemOpen(open_action != 0);
6183 IMGUI_DEMO_MARKER("Tables/Nested tables");
6184 if (ImGui::TreeNode("Nested tables"))
6185 {
6186 HelpMarker("This demonstrates embedding a table into another table cell.");
6187
6188 if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6189 {
6190 ImGui::TableSetupColumn("A0");
6191 ImGui::TableSetupColumn("A1");
6192 ImGui::TableHeadersRow();
6193
6194 ImGui::TableNextColumn();
6195 ImGui::Text("A0 Row 0");
6196 {
6197 float rows_height = TEXT_BASE_HEIGHT * 2;
6198 if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6199 {
6200 ImGui::TableSetupColumn("B0");
6201 ImGui::TableSetupColumn("B1");
6202 ImGui::TableHeadersRow();
6203
6204 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6205 ImGui::TableNextColumn();
6206 ImGui::Text("B0 Row 0");
6207 ImGui::TableNextColumn();
6208 ImGui::Text("B1 Row 0");
6209 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
6210 ImGui::TableNextColumn();
6211 ImGui::Text("B0 Row 1");
6212 ImGui::TableNextColumn();
6213 ImGui::Text("B1 Row 1");
6214
6215 ImGui::EndTable();
6216 }
6217 }
6218 ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
6219 ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
6220 ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
6221 ImGui::EndTable();
6222 }
6223 ImGui::TreePop();
6224 }
6225
6226 if (open_action != -1)
6227 ImGui::SetNextItemOpen(open_action != 0);
6228 IMGUI_DEMO_MARKER("Tables/Row height");
6229 if (ImGui::TreeNode("Row height"))
6230 {
6231 HelpMarker(
6232 "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
6233 "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
6234 "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
6235 if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
6236 {
6237 for (int row = 0; row < 8; row++)
6238 {
6239 float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
6240 ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
6241 ImGui::TableNextColumn();
6242 ImGui::Text("min_row_height = %.2f", min_row_height);
6243 }
6244 ImGui::EndTable();
6245 }
6246
6247 HelpMarker(
6248 "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
6249 "Please note that Tables Row Height is not the same thing as Current Line Height, "
6250 "as a table cell may contains multiple lines.");
6251 if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
6252 {
6253 ImGui::TableNextRow();
6254 ImGui::TableNextColumn();
6255 ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6256 ImGui::TableNextColumn();
6257 ImGui::Text("Line 1");
6258 ImGui::Text("Line 2");
6259
6260 ImGui::TableNextRow();
6261 ImGui::TableNextColumn();
6262 ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
6263 ImGui::TableNextColumn();
6264 ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
6265 ImGui::Text("Line 1, with SameLine(0,0)");
6266 ImGui::Text("Line 2");
6267
6268 ImGui::EndTable();
6269 }
6270
6271 HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
6272 if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
6273 {
6274 ImGuiStyle& style = ImGui::GetStyle();
6275 for (int row = 0; row < 8; row++)
6276 {
6277 if ((row % 3) == 2)
6278 ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f);
6279 ImGui::TableNextRow(ImGuiTableRowFlags_None);
6280 ImGui::TableNextColumn();
6281 ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
6282 if ((row % 3) == 2)
6283 ImGui::PopStyleVar();
6284 }
6285 ImGui::EndTable();
6286 }
6287
6288 ImGui::TreePop();
6289 }
6290
6291 if (open_action != -1)
6292 ImGui::SetNextItemOpen(open_action != 0);
6293 IMGUI_DEMO_MARKER("Tables/Outer size");
6294 if (ImGui::TreeNode("Outer size"))
6295 {
6296 // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
6297 // Important to that note how the two flags have slightly different behaviors!
6298 ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
6299 PushStyleCompact();
6300 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
6301 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6302 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
6303 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6304 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
6305 PopStyleCompact();
6306
6307 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
6308 if (ImGui::BeginTable("table1", 3, flags, outer_size))
6309 {
6310 for (int row = 0; row < 10; row++)
6311 {
6312 ImGui::TableNextRow();
6313 for (int column = 0; column < 3; column++)
6314 {
6315 ImGui::TableNextColumn();
6316 ImGui::Text("Cell %d,%d", column, row);
6317 }
6318 }
6319 ImGui::EndTable();
6320 }
6321 ImGui::SameLine();
6322 ImGui::Text("Hello!");
6323
6324 ImGui::Spacing();
6325
6326 ImGui::Text("Using explicit size:");
6327 if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6328 {
6329 for (int row = 0; row < 5; row++)
6330 {
6331 ImGui::TableNextRow();
6332 for (int column = 0; column < 3; column++)
6333 {
6334 ImGui::TableNextColumn();
6335 ImGui::Text("Cell %d,%d", column, row);
6336 }
6337 }
6338 ImGui::EndTable();
6339 }
6340 ImGui::SameLine();
6341 if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
6342 {
6343 for (int row = 0; row < 3; row++)
6344 {
6345 ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f);
6346 for (int column = 0; column < 3; column++)
6347 {
6348 ImGui::TableNextColumn();
6349 ImGui::Text("Cell %d,%d", column, row);
6350 }
6351 }
6352 ImGui::EndTable();
6353 }
6354
6355 ImGui::TreePop();
6356 }
6357
6358 if (open_action != -1)
6359 ImGui::SetNextItemOpen(open_action != 0);
6360 IMGUI_DEMO_MARKER("Tables/Background color");
6361 if (ImGui::TreeNode("Background color"))
6362 {
6363 static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
6364 static int row_bg_type = 1;
6365 static int row_bg_target = 1;
6366 static int cell_bg_type = 1;
6367
6368 PushStyleCompact();
6369 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
6370 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6371 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
6372 ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
6373 ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.");
6374 ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
6375 IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
6376 IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
6377 IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
6378 PopStyleCompact();
6379
6380 if (ImGui::BeginTable("table1", 5, flags))
6381 {
6382 for (int row = 0; row < 6; row++)
6383 {
6384 ImGui::TableNextRow();
6385
6386 // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
6387 // We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag.
6388 if (row_bg_type != 0)
6389 {
6390 ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient?
6391 ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
6392 }
6393
6394 // Fill cells
6395 for (int column = 0; column < 5; column++)
6396 {
6397 ImGui::TableSetColumnIndex(column);
6398 ImGui::Text("%c%c", 'A' + row, '0' + column);
6399
6400 // Change background of Cells B1->C2
6401 // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
6402 // (the CellBg color will be blended over the RowBg and ColumnBg colors)
6403 // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
6404 if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
6405 {
6406 ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
6407 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
6408 }
6409 }
6410 }
6411 ImGui::EndTable();
6412 }
6413 ImGui::TreePop();
6414 }
6415
6416 if (open_action != -1)
6417 ImGui::SetNextItemOpen(open_action != 0);
6418 IMGUI_DEMO_MARKER("Tables/Tree view");
6419 if (ImGui::TreeNode("Tree view"))
6420 {
6421 static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
6422
6423 static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
6424 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
6425 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth);
6426 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns);
6427
6428 HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
6429 if (ImGui::BeginTable("3ways", 3, flags))
6430 {
6431 // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
6432 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
6433 ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
6434 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
6435 ImGui::TableHeadersRow();
6436
6437 // Simple storage to output a dummy file-system.
6438 struct MyTreeNode
6439 {
6440 const char* Name;
6441 const char* Type;
6442 int Size;
6443 int ChildIdx;
6444 int ChildCount;
6445 static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
6446 {
6447 ImGui::TableNextRow();
6448 ImGui::TableNextColumn();
6449 const bool is_folder = (node->ChildCount > 0);
6450 if (is_folder)
6451 {
6452 bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags);
6453 ImGui::TableNextColumn();
6454 ImGui::TextDisabled("--");
6455 ImGui::TableNextColumn();
6456 ImGui::TextUnformatted(node->Type);
6457 if (open)
6458 {
6459 for (int child_n = 0; child_n < node->ChildCount; child_n++)
6460 DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
6461 ImGui::TreePop();
6462 }
6463 }
6464 else
6465 {
6466 ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
6467 ImGui::TableNextColumn();
6468 ImGui::Text("%d", node->Size);
6469 ImGui::TableNextColumn();
6470 ImGui::TextUnformatted(node->Type);
6471 }
6472 }
6473 };
6474 static const MyTreeNode nodes[] =
6475 {
6476 { "Root", "Folder", -1, 1, 3 }, // 0
6477 { "Music", "Folder", -1, 4, 2 }, // 1
6478 { "Textures", "Folder", -1, 6, 3 }, // 2
6479 { "desktop.ini", "System file", 1024, -1,-1 }, // 3
6480 { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4
6481 { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5
6482 { "Image001.png", "Image file", 203128, -1,-1 }, // 6
6483 { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7
6484 { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8
6485 };
6486
6487 MyTreeNode::DisplayNode(&nodes[0], nodes);
6488
6489 ImGui::EndTable();
6490 }
6491 ImGui::TreePop();
6492 }
6493
6494 if (open_action != -1)
6495 ImGui::SetNextItemOpen(open_action != 0);
6496 IMGUI_DEMO_MARKER("Tables/Item width");
6497 if (ImGui::TreeNode("Item width"))
6498 {
6499 HelpMarker(
6500 "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
6501 "Note that on auto-resizing non-resizable fixed columns, querying the content width for "
6502 "e.g. right-alignment doesn't make sense.");
6503 if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
6504 {
6505 ImGui::TableSetupColumn("small");
6506 ImGui::TableSetupColumn("half");
6507 ImGui::TableSetupColumn("right-align");
6508 ImGui::TableHeadersRow();
6509
6510 for (int row = 0; row < 3; row++)
6511 {
6512 ImGui::TableNextRow();
6513 if (row == 0)
6514 {
6515 // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
6516 ImGui::TableSetColumnIndex(0);
6517 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
6518 ImGui::TableSetColumnIndex(1);
6519 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
6520 ImGui::TableSetColumnIndex(2);
6521 ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
6522 }
6523
6524 // Draw our contents
6525 static float dummy_f = 0.0f;
6526 ImGui::PushID(row);
6527 ImGui::TableSetColumnIndex(0);
6528 ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
6529 ImGui::TableSetColumnIndex(1);
6530 ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
6531 ImGui::TableSetColumnIndex(2);
6532 ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned
6533 ImGui::PopID();
6534 }
6535 ImGui::EndTable();
6536 }
6537 ImGui::TreePop();
6538 }
6539
6540 // Demonstrate using TableHeader() calls instead of TableHeadersRow()
6541 if (open_action != -1)
6542 ImGui::SetNextItemOpen(open_action != 0);
6543 IMGUI_DEMO_MARKER("Tables/Custom headers");
6544 if (ImGui::TreeNode("Custom headers"))
6545 {
6546 const int COLUMNS_COUNT = 3;
6547 if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
6548 {
6549 ImGui::TableSetupColumn("Apricot");
6550 ImGui::TableSetupColumn("Banana");
6551 ImGui::TableSetupColumn("Cherry");
6552
6553 // Dummy entire-column selection storage
6554 // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
6555 static bool column_selected[3] = {};
6556
6557 // Instead of calling TableHeadersRow() we'll submit custom headers ourselves.
6558 // (A different approach is also possible:
6559 // - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call.
6560 // - Call TableHeadersRow() normally. This will submit TableHeader() with no name.
6561 // - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().)
6562 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
6563 for (int column = 0; column < COLUMNS_COUNT; column++)
6564 {
6565 ImGui::TableSetColumnIndex(column);
6566 const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
6567 ImGui::PushID(column);
6568 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
6569 ImGui::Checkbox("##checkall", &column_selected[column]);
6570 ImGui::PopStyleVar();
6571 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
6572 ImGui::TableHeader(column_name);
6573 ImGui::PopID();
6574 }
6575
6576 // Submit table contents
6577 for (int row = 0; row < 5; row++)
6578 {
6579 ImGui::TableNextRow();
6580 for (int column = 0; column < 3; column++)
6581 {
6582 char buf[32];
6583 sprintf(buf, "Cell %d,%d", column, row);
6584 ImGui::TableSetColumnIndex(column);
6585 ImGui::Selectable(buf, column_selected[column]);
6586 }
6587 }
6588 ImGui::EndTable();
6589 }
6590 ImGui::TreePop();
6591 }
6592
6593 // Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
6594 if (open_action != -1)
6595 ImGui::SetNextItemOpen(open_action != 0);
6596 IMGUI_DEMO_MARKER("Tables/Angled headers");
6597 if (ImGui::TreeNode("Angled headers"))
6598 {
6599 const char* column_names[] = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" };
6600 const int columns_count = IM_ARRAYSIZE(column_names);
6601 const int rows_count = 12;
6602
6603 static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
6604 static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
6605 static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
6606 static int frozen_cols = 1;
6607 static int frozen_rows = 2;
6608 ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
6609 ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
6610 ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
6611 ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable);
6612 ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
6613 ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
6614 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6615 ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2);
6616 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6617 ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
6618 ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
6619
6620 if (ImGui::TreeNode("Style settings"))
6621 {
6622 ImGui::SameLine();
6623 HelpMarker("Giving access to some ImGuiStyle value in this demo for convenience.");
6624 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6625 ImGui::SliderAngle("style.TableAngledHeadersAngle", &ImGui::GetStyle().TableAngledHeadersAngle, -50.0f, +50.0f);
6626 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6627 ImGui::SliderFloat2("style.TableAngledHeadersTextAlign", (float*)&ImGui::GetStyle().TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
6628 ImGui::TreePop();
6629 }
6630
6631 if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
6632 {
6633 ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
6634 for (int n = 1; n < columns_count; n++)
6635 ImGui::TableSetupColumn(column_names[n], column_flags);
6636 ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows);
6637
6638 ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
6639 ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions.
6640 for (int row = 0; row < rows_count; row++)
6641 {
6642 ImGui::PushID(row);
6643 ImGui::TableNextRow();
6644 ImGui::TableSetColumnIndex(0);
6645 ImGui::AlignTextToFramePadding();
6646 ImGui::Text("Track %d", row);
6647 for (int column = 1; column < columns_count; column++)
6648 if (ImGui::TableSetColumnIndex(column))
6649 {
6650 ImGui::PushID(column);
6651 ImGui::Checkbox("", &bools[row * columns_count + column]);
6652 ImGui::PopID();
6653 }
6654 ImGui::PopID();
6655 }
6656 ImGui::EndTable();
6657 }
6658 ImGui::TreePop();
6659 }
6660
6661 // Demonstrate creating custom context menus inside columns,
6662 // while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
6663 if (open_action != -1)
6664 ImGui::SetNextItemOpen(open_action != 0);
6665 IMGUI_DEMO_MARKER("Tables/Context menus");
6666 if (ImGui::TreeNode("Context menus"))
6667 {
6668 HelpMarker(
6669 "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
6670 "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
6671 static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
6672
6673 PushStyleCompact();
6674 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
6675 PopStyleCompact();
6676
6677 // Context Menus: first example
6678 // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6679 // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
6680 const int COLUMNS_COUNT = 3;
6681 if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
6682 {
6683 ImGui::TableSetupColumn("One");
6684 ImGui::TableSetupColumn("Two");
6685 ImGui::TableSetupColumn("Three");
6686
6687 // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
6688 ImGui::TableHeadersRow();
6689
6690 // Submit dummy contents
6691 for (int row = 0; row < 4; row++)
6692 {
6693 ImGui::TableNextRow();
6694 for (int column = 0; column < COLUMNS_COUNT; column++)
6695 {
6696 ImGui::TableSetColumnIndex(column);
6697 ImGui::Text("Cell %d,%d", column, row);
6698 }
6699 }
6700 ImGui::EndTable();
6701 }
6702
6703 // Context Menus: second example
6704 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6705 // [2.2] Right-click on the ".." to open a custom popup
6706 // [2.3] Right-click in columns to open another custom popup
6707 HelpMarker(
6708 "Demonstrate mixing table context menu (over header), item context button (over button) "
6709 "and custom per-colunm context menu (over column body).");
6710 ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
6711 if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
6712 {
6713 ImGui::TableSetupColumn("One");
6714 ImGui::TableSetupColumn("Two");
6715 ImGui::TableSetupColumn("Three");
6716
6717 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
6718 ImGui::TableHeadersRow();
6719 for (int row = 0; row < 4; row++)
6720 {
6721 ImGui::TableNextRow();
6722 for (int column = 0; column < COLUMNS_COUNT; column++)
6723 {
6724 // Submit dummy contents
6725 ImGui::TableSetColumnIndex(column);
6726 ImGui::Text("Cell %d,%d", column, row);
6727 ImGui::SameLine();
6728
6729 // [2.2] Right-click on the ".." to open a custom popup
6730 ImGui::PushID(row * COLUMNS_COUNT + column);
6731 ImGui::SmallButton("..");
6732 if (ImGui::BeginPopupContextItem())
6733 {
6734 ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
6735 if (ImGui::Button("Close"))
6736 ImGui::CloseCurrentPopup();
6737 ImGui::EndPopup();
6738 }
6739 ImGui::PopID();
6740 }
6741 }
6742
6743 // [2.3] Right-click anywhere in columns to open another custom popup
6744 // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
6745 // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
6746 int hovered_column = -1;
6747 for (int column = 0; column < COLUMNS_COUNT + 1; column++)
6748 {
6749 ImGui::PushID(column);
6750 if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
6751 hovered_column = column;
6752 if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
6753 ImGui::OpenPopup("MyPopup");
6754 if (ImGui::BeginPopup("MyPopup"))
6755 {
6756 if (column == COLUMNS_COUNT)
6757 ImGui::Text("This is a custom popup for unused space after the last column.");
6758 else
6759 ImGui::Text("This is a custom popup for Column %d", column);
6760 if (ImGui::Button("Close"))
6761 ImGui::CloseCurrentPopup();
6762 ImGui::EndPopup();
6763 }
6764 ImGui::PopID();
6765 }
6766
6767 ImGui::EndTable();
6768 ImGui::Text("Hovered column: %d", hovered_column);
6769 }
6770 ImGui::TreePop();
6771 }
6772
6773 // Demonstrate creating multiple tables with the same ID
6774 if (open_action != -1)
6775 ImGui::SetNextItemOpen(open_action != 0);
6776 IMGUI_DEMO_MARKER("Tables/Synced instances");
6777 if (ImGui::TreeNode("Synced instances"))
6778 {
6779 HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
6780
6781 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
6782 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6783 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6784 ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
6785 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
6786 for (int n = 0; n < 3; n++)
6787 {
6788 char buf[32];
6789 sprintf(buf, "Synced Table %d", n);
6790 bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
6791 if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
6792 {
6793 ImGui::TableSetupColumn("One");
6794 ImGui::TableSetupColumn("Two");
6795 ImGui::TableSetupColumn("Three");
6796 ImGui::TableHeadersRow();
6797 const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
6798 for (int cell = 0; cell < cell_count; cell++)
6799 {
6800 ImGui::TableNextColumn();
6801 ImGui::Text("this cell %d", cell);
6802 }
6803 ImGui::EndTable();
6804 }
6805 }
6806 ImGui::TreePop();
6807 }
6808
6809 // Demonstrate using Sorting facilities
6810 // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
6811 // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
6812 static const char* template_items_names[] =
6813 {
6814 "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
6815 "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
6816 };
6817 if (open_action != -1)
6818 ImGui::SetNextItemOpen(open_action != 0);
6819 IMGUI_DEMO_MARKER("Tables/Sorting");
6820 if (ImGui::TreeNode("Sorting"))
6821 {
6822 // Create item list
6823 static ImVector<MyItem> items;
6824 if (items.Size == 0)
6825 {
6826 items.resize(50, MyItem());
6827 for (int n = 0; n < items.Size; n++)
6828 {
6829 const int template_n = n % IM_ARRAYSIZE(template_items_names);
6830 MyItem& item = items[n];
6831 item.ID = n;
6832 item.Name = template_items_names[template_n];
6833 item.Quantity = (n * n - n) % 20; // Assign default quantities
6834 }
6835 }
6836
6837 // Options
6838 static ImGuiTableFlags flags =
6839 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6840 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
6841 | ImGuiTableFlags_ScrollY;
6842 PushStyleCompact();
6843 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
6844 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
6845 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
6846 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
6847 PopStyleCompact();
6848
6849 if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
6850 {
6851 // Declare columns
6852 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
6853 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
6854 // Demonstrate using a mixture of flags among available sort-related flags:
6855 // - ImGuiTableColumnFlags_DefaultSort
6856 // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
6857 // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
6858 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID);
6859 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
6860 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
6861 ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
6862 ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
6863 ImGui::TableHeadersRow();
6864
6865 // Sort our data if sort specs have been changed!
6866 if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
6867 if (sort_specs->SpecsDirty)
6868 {
6869 MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
6870 sort_specs->SpecsDirty = false;
6871 }
6872
6873 // Demonstrate using clipper for large vertical lists
6874 ImGuiListClipper clipper;
6875 clipper.Begin(items.Size);
6876 while (clipper.Step())
6877 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
6878 {
6879 // Display a data item
6880 MyItem* item = &items[row_n];
6881 ImGui::PushID(item->ID);
6882 ImGui::TableNextRow();
6883 ImGui::TableNextColumn();
6884 ImGui::Text("%04d", item->ID);
6885 ImGui::TableNextColumn();
6886 ImGui::TextUnformatted(item->Name);
6887 ImGui::TableNextColumn();
6888 ImGui::SmallButton("None");
6889 ImGui::TableNextColumn();
6890 ImGui::Text("%d", item->Quantity);
6891 ImGui::PopID();
6892 }
6893 ImGui::EndTable();
6894 }
6895 ImGui::TreePop();
6896 }
6897
6898 // In this example we'll expose most table flags and settings.
6899 // For specific flags and settings refer to the corresponding section for more detailed explanation.
6900 // This section is mostly useful to experiment with combining certain flags or settings with each others.
6901 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
6902 if (open_action != -1)
6903 ImGui::SetNextItemOpen(open_action != 0);
6904 IMGUI_DEMO_MARKER("Tables/Advanced");
6905 if (ImGui::TreeNode("Advanced"))
6906 {
6907 static ImGuiTableFlags flags =
6908 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
6909 | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
6910 | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
6911 | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
6912 | ImGuiTableFlags_SizingFixedFit;
6913 static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
6914
6915 enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
6916 static int contents_type = CT_SelectableSpanRow;
6917 const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
6918 static int freeze_cols = 1;
6919 static int freeze_rows = 1;
6920 static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
6921 static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
6922 static float row_min_height = 0.0f; // Auto
6923 static float inner_width_with_scroll = 0.0f; // Auto-extend
6924 static bool outer_size_enabled = true;
6925 static bool show_headers = true;
6926 static bool show_wrapped_text = false;
6927 //static ImGuiTextFilter filter;
6928 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
6929 if (ImGui::TreeNode("Options"))
6930 {
6931 // Make the UI compact because there are so many fields
6932 PushStyleCompact();
6933 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
6934
6935 if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
6936 {
6937 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
6938 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
6939 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
6940 ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
6941 ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
6942 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
6943 ImGui::TreePop();
6944 }
6945
6946 if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
6947 {
6948 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
6949 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
6950 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
6951 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
6952 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
6953 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
6954 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
6955 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
6956 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
6957 ImGui::TreePop();
6958 }
6959
6960 if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
6961 {
6962 EditTableSizingFlags(&flags);
6963 ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
6964 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
6965 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
6966 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
6967 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
6968 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
6969 ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
6970 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
6971 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
6972 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
6973 ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.");
6974 ImGui::TreePop();
6975 }
6976
6977 if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
6978 {
6979 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
6980 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
6981 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
6982 ImGui::TreePop();
6983 }
6984
6985 if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
6986 {
6987 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
6988 ImGui::SameLine();
6989 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6990 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6991 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
6992 ImGui::SameLine();
6993 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
6994 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
6995 ImGui::TreePop();
6996 }
6997
6998 if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
6999 {
7000 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
7001 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
7002 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
7003 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
7004 ImGui::TreePop();
7005 }
7006
7007 if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
7008 {
7009 ImGui::Checkbox("show_headers", &show_headers);
7010 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
7011 ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
7012 ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
7013 ImGui::TreePop();
7014 }
7015
7016 if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
7017 {
7018 ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
7019
7020 ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
7021 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7022 ImGui::Checkbox("outer_size", &outer_size_enabled);
7023 ImGui::SameLine();
7024 HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
7025 "- The table is output directly in the parent window.\n"
7026 "- OuterSize.x < 0.0f will right-align the table.\n"
7027 "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
7028 "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
7029
7030 // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
7031 // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
7032 ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
7033
7034 ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
7035 ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
7036
7037 ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
7038 ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
7039 //filter.Draw("filter");
7040 ImGui::TreePop();
7041 }
7042
7043 ImGui::PopItemWidth();
7044 PopStyleCompact();
7045 ImGui::Spacing();
7046 ImGui::TreePop();
7047 }
7048
7049 // Update item list if we changed the number of items
7050 static ImVector<MyItem> items;
7051 static ImVector<int> selection;
7052 static bool items_need_sort = false;
7053 if (items.Size != items_count)
7054 {
7055 items.resize(items_count, MyItem());
7056 for (int n = 0; n < items_count; n++)
7057 {
7058 const int template_n = n % IM_ARRAYSIZE(template_items_names);
7059 MyItem& item = items[n];
7060 item.ID = n;
7061 item.Name = template_items_names[template_n];
7062 item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
7063 }
7064 }
7065
7066 const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
7067 const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
7068 ImVec2 table_scroll_cur, table_scroll_max; // For debug display
7069 const ImDrawList* table_draw_list = NULL; // "
7070
7071 // Submit table
7072 const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
7073 if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
7074 {
7075 // Declare columns
7076 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
7077 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
7078 ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
7079 ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
7080 ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
7081 ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
7082 ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
7083 ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
7084 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
7085
7086 // Sort our data if sort specs have been changed!
7087 ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
7088 if (sort_specs && sort_specs->SpecsDirty)
7089 items_need_sort = true;
7090 if (sort_specs && items_need_sort && items.Size > 1)
7091 {
7092 MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
7093 sort_specs->SpecsDirty = false;
7094 }
7095 items_need_sort = false;
7096
7097 // Take note of whether we are currently sorting based on the Quantity field,
7098 // we will use this to trigger sorting when we know the data of this column has been modified.
7099 const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
7100
7101 // Show headers
7102 if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
7103 ImGui::TableAngledHeadersRow();
7104 if (show_headers)
7105 ImGui::TableHeadersRow();
7106
7107 // Show data
7108 // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
7109#if 1
7110 // Demonstrate using clipper for large vertical lists
7111 ImGuiListClipper clipper;
7112 clipper.Begin(items.Size);
7113 while (clipper.Step())
7114 {
7115 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
7116#else
7117 // Without clipper
7118 {
7119 for (int row_n = 0; row_n < items.Size; row_n++)
7120#endif
7121 {
7122 MyItem* item = &items[row_n];
7123 //if (!filter.PassFilter(item->Name))
7124 // continue;
7125
7126 const bool item_is_selected = selection.contains(item->ID);
7127 ImGui::PushID(item->ID);
7128 ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
7129
7130 // For the demo purpose we can select among different type of items submitted in the first column
7131 ImGui::TableSetColumnIndex(0);
7132 char label[32];
7133 sprintf(label, "%04d", item->ID);
7134 if (contents_type == CT_Text)
7136 else if (contents_type == CT_Button)
7137 ImGui::Button(label);
7138 else if (contents_type == CT_SmallButton)
7139 ImGui::SmallButton(label);
7140 else if (contents_type == CT_FillButton)
7141 ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
7142 else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
7143 {
7144 ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
7145 if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
7146 {
7147 if (ImGui::GetIO().KeyCtrl)
7148 {
7149 if (item_is_selected)
7150 selection.find_erase_unsorted(item->ID);
7151 else
7152 selection.push_back(item->ID);
7153 }
7154 else
7155 {
7156 selection.clear();
7157 selection.push_back(item->ID);
7158 }
7159 }
7160 }
7161
7162 if (ImGui::TableSetColumnIndex(1))
7163 ImGui::TextUnformatted(item->Name);
7164
7165 // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
7166 // and we are currently sorting on the column showing the Quantity.
7167 // To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
7168 // You will probably need some extra logic if you want to automatically sort when a specific entry changes.
7169 if (ImGui::TableSetColumnIndex(2))
7170 {
7171 if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
7172 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7173 ImGui::SameLine();
7174 if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
7175 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
7176 }
7177
7178 if (ImGui::TableSetColumnIndex(3))
7179 ImGui::Text("%d", item->Quantity);
7180
7181 ImGui::TableSetColumnIndex(4);
7182 if (show_wrapped_text)
7183 ImGui::TextWrapped("Lorem ipsum dolor sit amet");
7184 else
7185 ImGui::Text("Lorem ipsum dolor sit amet");
7186
7187 if (ImGui::TableSetColumnIndex(5))
7188 ImGui::Text("1234");
7189
7190 ImGui::PopID();
7191 }
7192 }
7193
7194 // Store some info to display debug details below
7195 table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
7196 table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
7197 table_draw_list = ImGui::GetWindowDrawList();
7198 ImGui::EndTable();
7199 }
7200 static bool show_debug_details = false;
7201 ImGui::Checkbox("Debug details", &show_debug_details);
7202 if (show_debug_details && table_draw_list)
7203 {
7204 ImGui::SameLine(0.0f, 0.0f);
7205 const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
7206 if (table_draw_list == parent_draw_list)
7207 ImGui::Text(": DrawCmd: +%d (in same window)",
7208 table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
7209 else
7210 ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
7211 table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
7212 }
7213 ImGui::TreePop();
7214 }
7215
7216 ImGui::PopID();
7217
7218 ShowDemoWindowColumns();
7219
7220 if (disable_indent)
7221 ImGui::PopStyleVar();
7222}
7223
7224// Demonstrate old/legacy Columns API!
7225// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
7226static void ShowDemoWindowColumns()
7227{
7228 IMGUI_DEMO_MARKER("Columns (legacy API)");
7229 bool open = ImGui::TreeNode("Legacy Columns API");
7230 ImGui::SameLine();
7231 HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
7232 if (!open)
7233 return;
7234
7235 // Basic columns
7236 IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
7237 if (ImGui::TreeNode("Basic"))
7238 {
7239 ImGui::Text("Without border:");
7240 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
7241 ImGui::Separator();
7242 for (int n = 0; n < 14; n++)
7243 {
7244 char label[32];
7245 sprintf(label, "Item %d", n);
7246 if (ImGui::Selectable(label)) {}
7247 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
7248 ImGui::NextColumn();
7249 }
7250 ImGui::Columns(1);
7251 ImGui::Separator();
7252
7253 ImGui::Text("With border:");
7254 ImGui::Columns(4, "mycolumns"); // 4-ways, with border
7255 ImGui::Separator();
7256 ImGui::Text("ID"); ImGui::NextColumn();
7257 ImGui::Text("Name"); ImGui::NextColumn();
7258 ImGui::Text("Path"); ImGui::NextColumn();
7259 ImGui::Text("Hovered"); ImGui::NextColumn();
7260 ImGui::Separator();
7261 const char* names[3] = { "One", "Two", "Three" };
7262 const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
7263 static int selected = -1;
7264 for (int i = 0; i < 3; i++)
7265 {
7266 char label[32];
7267 sprintf(label, "%04d", i);
7268 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
7269 selected = i;
7270 bool hovered = ImGui::IsItemHovered();
7271 ImGui::NextColumn();
7272 ImGui::Text(names[i]); ImGui::NextColumn();
7273 ImGui::Text(paths[i]); ImGui::NextColumn();
7274 ImGui::Text("%d", hovered); ImGui::NextColumn();
7275 }
7276 ImGui::Columns(1);
7277 ImGui::Separator();
7278 ImGui::TreePop();
7279 }
7280
7281 IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
7282 if (ImGui::TreeNode("Borders"))
7283 {
7284 // NB: Future columns API should allow automatic horizontal borders.
7285 static bool h_borders = true;
7286 static bool v_borders = true;
7287 static int columns_count = 4;
7288 const int lines_count = 3;
7289 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
7290 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
7291 if (columns_count < 2)
7292 columns_count = 2;
7293 ImGui::SameLine();
7294 ImGui::Checkbox("horizontal", &h_borders);
7295 ImGui::SameLine();
7296 ImGui::Checkbox("vertical", &v_borders);
7297 ImGui::Columns(columns_count, NULL, v_borders);
7298 for (int i = 0; i < columns_count * lines_count; i++)
7299 {
7300 if (h_borders && ImGui::GetColumnIndex() == 0)
7301 ImGui::Separator();
7302 ImGui::PushID(i);
7303 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
7304 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
7305 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
7306 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
7307 ImGui::Text("Long text that is likely to clip");
7308 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
7309 ImGui::PopID();
7310 ImGui::NextColumn();
7311 }
7312 ImGui::Columns(1);
7313 if (h_borders)
7314 ImGui::Separator();
7315 ImGui::TreePop();
7316 }
7317
7318 // Create multiple items in a same cell before switching to next column
7319 IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
7320 if (ImGui::TreeNode("Mixed items"))
7321 {
7322 ImGui::Columns(3, "mixed");
7323 ImGui::Separator();
7324
7325 ImGui::Text("Hello");
7326 ImGui::Button("Banana");
7327 ImGui::NextColumn();
7328
7329 ImGui::Text("ImGui");
7330 ImGui::Button("Apple");
7331 static float foo = 1.0f;
7332 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
7333 ImGui::Text("An extra line here.");
7334 ImGui::NextColumn();
7335
7336 ImGui::Text("Sailor");
7337 ImGui::Button("Corniflower");
7338 static float bar = 1.0f;
7339 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
7340 ImGui::NextColumn();
7341
7342 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7343 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7344 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
7345 ImGui::Columns(1);
7346 ImGui::Separator();
7347 ImGui::TreePop();
7348 }
7349
7350 // Word wrapping
7351 IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
7352 if (ImGui::TreeNode("Word-wrapping"))
7353 {
7354 ImGui::Columns(2, "word-wrapping");
7355 ImGui::Separator();
7356 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7357 ImGui::TextWrapped("Hello Left");
7358 ImGui::NextColumn();
7359 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
7360 ImGui::TextWrapped("Hello Right");
7361 ImGui::Columns(1);
7362 ImGui::Separator();
7363 ImGui::TreePop();
7364 }
7365
7366 IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
7367 if (ImGui::TreeNode("Horizontal Scrolling"))
7368 {
7369 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
7370 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
7371 ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
7372 ImGui::Columns(10);
7373
7374 // Also demonstrate using clipper for large vertical lists
7375 int ITEMS_COUNT = 2000;
7376 ImGuiListClipper clipper;
7377 clipper.Begin(ITEMS_COUNT);
7378 while (clipper.Step())
7379 {
7380 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7381 for (int j = 0; j < 10; j++)
7382 {
7383 ImGui::Text("Line %d Column %d...", i, j);
7384 ImGui::NextColumn();
7385 }
7386 }
7387 ImGui::Columns(1);
7388 ImGui::EndChild();
7389 ImGui::TreePop();
7390 }
7391
7392 IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
7393 if (ImGui::TreeNode("Tree"))
7394 {
7395 ImGui::Columns(2, "tree", true);
7396 for (int x = 0; x < 3; x++)
7397 {
7398 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
7399 ImGui::NextColumn();
7400 ImGui::Text("Node contents");
7401 ImGui::NextColumn();
7402 if (open1)
7403 {
7404 for (int y = 0; y < 3; y++)
7405 {
7406 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
7407 ImGui::NextColumn();
7408 ImGui::Text("Node contents");
7409 if (open2)
7410 {
7411 ImGui::Text("Even more contents");
7412 if (ImGui::TreeNode("Tree in column"))
7413 {
7414 ImGui::Text("The quick brown fox jumps over the lazy dog");
7415 ImGui::TreePop();
7416 }
7417 }
7418 ImGui::NextColumn();
7419 if (open2)
7420 ImGui::TreePop();
7421 }
7422 ImGui::TreePop();
7423 }
7424 }
7425 ImGui::Columns(1);
7426 ImGui::TreePop();
7427 }
7428
7429 ImGui::TreePop();
7430}
7431
7432//-----------------------------------------------------------------------------
7433// [SECTION] ShowDemoWindowInputs()
7434//-----------------------------------------------------------------------------
7435
7436static void ShowDemoWindowInputs()
7437{
7438 IMGUI_DEMO_MARKER("Inputs & Focus");
7439 if (ImGui::CollapsingHeader("Inputs & Focus"))
7440 {
7441 ImGuiIO& io = ImGui::GetIO();
7442
7443 // Display inputs submitted to ImGuiIO
7444 IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
7445 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7446 bool inputs_opened = ImGui::TreeNode("Inputs");
7447 ImGui::SameLine();
7448 HelpMarker(
7449 "This is a simplified view. See more detailed input state:\n"
7450 "- in 'Tools->Metrics/Debugger->Inputs'.\n"
7451 "- in 'Tools->Debug Log->IO'.");
7452 if (inputs_opened)
7453 {
7454 if (ImGui::IsMousePosValid())
7455 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
7456 else
7457 ImGui::Text("Mouse pos: <INVALID>");
7458 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
7459 ImGui::Text("Mouse down:");
7460 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
7461 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
7462
7463 // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
7464 // displaying the data for old/new backends.
7465 // User code should never have to go through such hoops!
7466 // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
7467 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
7468 ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
7469 ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); }
7470 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
7471 ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
7472
7473 ImGui::TreePop();
7474 }
7475
7476 // Display ImGuiIO output flags
7477 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
7478 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
7479 bool outputs_opened = ImGui::TreeNode("Outputs");
7480 ImGui::SameLine();
7481 HelpMarker(
7482 "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
7483 "to instruct your application of how to route inputs. Typically, when a value is true, it means "
7484 "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
7485 "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
7486 "and underlying application should ignore mouse inputs (in practice there are many and more subtle "
7487 "rules leading to how those flags are set).");
7488 if (outputs_opened)
7489 {
7490 ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
7491 ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
7492 ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
7493 ImGui::Text("io.WantTextInput: %d", io.WantTextInput);
7494 ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos);
7495 ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
7496
7497 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
7498 if (ImGui::TreeNode("WantCapture override"))
7499 {
7500 HelpMarker(
7501 "Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
7502 "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
7503 "and true when clicking.");
7504 static int capture_override_mouse = -1;
7505 static int capture_override_keyboard = -1;
7506 const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
7507 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7508 ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp);
7509 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
7510 ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp);
7511
7512 ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item
7513 if (ImGui::IsItemHovered() && capture_override_mouse != -1)
7514 ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
7515 if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
7516 ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
7517
7518 ImGui::TreePop();
7519 }
7520 ImGui::TreePop();
7521 }
7522
7523 // Demonstrate using Shortcut() and Routing Policies.
7524 // The general flow is:
7525 // - Code interested in a chord (e.g. "Ctrl+A") declares their intent.
7526 // - Multiple locations may be interested in same chord! Routing helps find a winner.
7527 // - Every frame, we resolve all claims and assign one owner if the modifiers are matching.
7528 // - The lower-level function is 'bool SetShortcutRouting()', returns true when caller got the route.
7529 // - Most of the times, SetShortcutRouting() is not called directly. User mostly calls Shortcut() with routing flags.
7530 // - If you call Shortcut() WITHOUT any routing option, it uses ImGuiInputFlags_RouteFocused.
7531 // TL;DR: Most uses will simply be:
7532 // - Shortcut(ImGuiMod_Ctrl | ImGuiKey_A); // Use ImGuiInputFlags_RouteFocused policy.
7533 IMGUI_DEMO_MARKER("Inputs & Focus/Shortcuts");
7534 if (ImGui::TreeNode("Shortcuts"))
7535 {
7536 static ImGuiInputFlags route_options = ImGuiInputFlags_Repeat;
7537 static ImGuiInputFlags route_type = ImGuiInputFlags_RouteFocused;
7538 ImGui::CheckboxFlags("ImGuiInputFlags_Repeat", &route_options, ImGuiInputFlags_Repeat);
7539 ImGui::RadioButton("ImGuiInputFlags_RouteActive", &route_type, ImGuiInputFlags_RouteActive);
7540 ImGui::RadioButton("ImGuiInputFlags_RouteFocused (default)", &route_type, ImGuiInputFlags_RouteFocused);
7541 ImGui::RadioButton("ImGuiInputFlags_RouteGlobal", &route_type, ImGuiInputFlags_RouteGlobal);
7542 ImGui::Indent();
7543 ImGui::BeginDisabled(route_type != ImGuiInputFlags_RouteGlobal);
7544 ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverFocused", &route_options, ImGuiInputFlags_RouteOverFocused);
7545 ImGui::CheckboxFlags("ImGuiInputFlags_RouteOverActive", &route_options, ImGuiInputFlags_RouteOverActive);
7546 ImGui::CheckboxFlags("ImGuiInputFlags_RouteUnlessBgFocused", &route_options, ImGuiInputFlags_RouteUnlessBgFocused);
7547 ImGui::EndDisabled();
7548 ImGui::Unindent();
7549 ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
7550 ImGuiInputFlags flags = route_type | route_options; // Merged flags
7551 if (route_type != ImGuiInputFlags_RouteGlobal)
7552 flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
7553
7554 ImGui::SeparatorText("Using SetNextItemShortcut()");
7555 ImGui::Text("Ctrl+S");
7556 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, flags | ImGuiInputFlags_Tooltip);
7557 ImGui::Button("Save");
7558 ImGui::Text("Alt+F");
7559 ImGui::SetNextItemShortcut(ImGuiMod_Alt | ImGuiKey_F, flags | ImGuiInputFlags_Tooltip);
7560 static float f = 0.5f;
7561 ImGui::SliderFloat("Factor", &f, 0.0f, 1.0f);
7562
7563 ImGui::SeparatorText("Using Shortcut()");
7564 const float line_height = ImGui::GetTextLineHeightWithSpacing();
7565 const ImGuiKeyChord key_chord = ImGuiMod_Ctrl | ImGuiKey_A;
7566
7567 ImGui::Text("Ctrl+A");
7568 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7569
7570 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 0.0f, 1.0f, 0.1f));
7571
7572 ImGui::BeginChild("WindowA", ImVec2(-FLT_MIN, line_height * 14), true);
7573 ImGui::Text("Press CTRL+A and see who receives it!");
7574 ImGui::Separator();
7575
7576 // 1: Window polling for CTRL+A
7577 ImGui::Text("(in WindowA)");
7578 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7579
7580 // 2: InputText also polling for CTRL+A: it always uses _RouteFocused internally (gets priority when active)
7581 // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7582 //char str[16] = "Press CTRL+A";
7583 //ImGui::Spacing();
7584 //ImGui::InputText("InputTextB", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7585 //ImGuiID item_id = ImGui::GetItemID();
7586 //ImGui::SameLine(); HelpMarker("Internal widgets always use _RouteFocused");
7587 //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, item_id) ? "PRESSED" : "...");
7588
7589 // 3: Dummy child is not claiming the route: focusing them shouldn't steal route away from WindowA
7590 ImGui::BeginChild("ChildD", ImVec2(-FLT_MIN, line_height * 4), true);
7591 ImGui::Text("(in ChildD: not using same Shortcut)");
7592 ImGui::Text("IsWindowFocused: %d", ImGui::IsWindowFocused());
7593 ImGui::EndChild();
7594
7595 // 4: Child window polling for CTRL+A. It is deeper than WindowA and gets priority when focused.
7596 ImGui::BeginChild("ChildE", ImVec2(-FLT_MIN, line_height * 4), true);
7597 ImGui::Text("(in ChildE: using same Shortcut)");
7598 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7599 ImGui::EndChild();
7600
7601 // 5: In a popup
7602 if (ImGui::Button("Open Popup"))
7603 ImGui::OpenPopup("PopupF");
7604 if (ImGui::BeginPopup("PopupF"))
7605 {
7606 ImGui::Text("(in PopupF)");
7607 ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "...");
7608 // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h)
7609 //ImGui::InputText("InputTextG", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly);
7610 //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "...");
7611 ImGui::EndPopup();
7612 }
7613 ImGui::EndChild();
7614 ImGui::PopStyleColor();
7615
7616 ImGui::TreePop();
7617 }
7618
7619 // Display mouse cursors
7620 IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
7621 if (ImGui::TreeNode("Mouse Cursors"))
7622 {
7623 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
7624 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
7625
7626 ImGuiMouseCursor current = ImGui::GetMouseCursor();
7627 const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
7628 ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
7629 ImGui::BeginDisabled(true);
7630 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
7631 ImGui::EndDisabled();
7632
7633 ImGui::Text("Hover to see mouse cursors:");
7634 ImGui::SameLine(); HelpMarker(
7635 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
7636 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
7637 "otherwise your backend needs to handle it.");
7638 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
7639 {
7640 char label[32];
7641 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
7642 ImGui::Bullet(); ImGui::Selectable(label, false);
7643 if (ImGui::IsItemHovered())
7644 ImGui::SetMouseCursor(i);
7645 }
7646 ImGui::TreePop();
7647 }
7648
7649 IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
7650 if (ImGui::TreeNode("Tabbing"))
7651 {
7652 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
7653 static char buf[32] = "hello";
7654 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7655 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7656 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
7657 ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7658 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
7659 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7660 ImGui::PopItemFlag();
7661 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
7662 ImGui::TreePop();
7663 }
7664
7665 IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
7666 if (ImGui::TreeNode("Focus from code"))
7667 {
7668 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
7669 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
7670 bool focus_3 = ImGui::Button("Focus on 3");
7671 int has_focus = 0;
7672 static char buf[128] = "click on a button to set focus";
7673
7674 if (focus_1) ImGui::SetKeyboardFocusHere();
7675 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
7676 if (ImGui::IsItemActive()) has_focus = 1;
7677
7678 if (focus_2) ImGui::SetKeyboardFocusHere();
7679 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
7680 if (ImGui::IsItemActive()) has_focus = 2;
7681
7682 ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
7683 if (focus_3) ImGui::SetKeyboardFocusHere();
7684 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
7685 if (ImGui::IsItemActive()) has_focus = 3;
7686 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
7687 ImGui::PopItemFlag();
7688
7689 if (has_focus)
7690 ImGui::Text("Item with focus: %d", has_focus);
7691 else
7692 ImGui::Text("Item with focus: <none>");
7693
7694 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
7695 static float f3[3] = { 0.0f, 0.0f, 0.0f };
7696 int focus_ahead = -1;
7697 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
7698 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
7699 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
7700 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
7701 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
7702
7703 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
7704 ImGui::TreePop();
7705 }
7706
7707 IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
7708 if (ImGui::TreeNode("Dragging"))
7709 {
7710 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
7711 for (int button = 0; button < 3; button++)
7712 {
7713 ImGui::Text("IsMouseDragging(%d):", button);
7714 ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button));
7715 ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
7716 ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
7717 }
7718
7719 ImGui::Button("Drag Me");
7720 if (ImGui::IsItemActive())
7721 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
7722
7723 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
7724 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
7725 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
7726 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
7727 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
7728 ImVec2 mouse_delta = io.MouseDelta;
7729 ImGui::Text("GetMouseDragDelta(0):");
7730 ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
7731 ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
7732 ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
7733 ImGui::TreePop();
7734 }
7735 }
7736}
7737
7738//-----------------------------------------------------------------------------
7739// [SECTION] About Window / ShowAboutWindow()
7740// Access from Dear ImGui Demo -> Tools -> About
7741//-----------------------------------------------------------------------------
7742
7743void ImGui::ShowAboutWindow(bool* p_open)
7744{
7745 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
7746 {
7747 ImGui::End();
7748 return;
7749 }
7750 IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
7751 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7752
7753 ImGui::TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui");
7754 ImGui::SameLine();
7755 ImGui::TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md");
7756 ImGui::SameLine();
7757 ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki");
7758 ImGui::SameLine();
7759 ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases");
7760 ImGui::SameLine();
7761 ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding");
7762
7763 ImGui::Separator();
7764 ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
7765 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
7766 ImGui::Text("If your company uses this, please consider funding the project.");
7767
7768 static bool show_config_info = false;
7769 ImGui::Checkbox("Config/Build Information", &show_config_info);
7770 if (show_config_info)
7771 {
7772 ImGuiIO& io = ImGui::GetIO();
7773 ImGuiStyle& style = ImGui::GetStyle();
7774
7775 bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
7776 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
7777 ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
7778 if (copy_to_clipboard)
7779 {
7780 ImGui::LogToClipboard();
7781 ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
7782 }
7783
7784 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
7785 ImGui::Separator();
7786 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
7787 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
7788#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
7789 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
7790#endif
7791#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
7792 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
7793#endif
7794#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
7795 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
7796#endif
7797#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
7798 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
7799#endif
7800#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
7801 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
7802#endif
7803#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
7804 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
7805#endif
7806#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
7807 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
7808#endif
7809#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
7810 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
7811#endif
7812#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
7813 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
7814#endif
7815#ifdef IMGUI_USE_BGRA_PACKED_COLOR
7816 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
7817#endif
7818#ifdef _WIN32
7819 ImGui::Text("define: _WIN32");
7820#endif
7821#ifdef _WIN64
7822 ImGui::Text("define: _WIN64");
7823#endif
7824#ifdef __linux__
7825 ImGui::Text("define: __linux__");
7826#endif
7827#ifdef __APPLE__
7828 ImGui::Text("define: __APPLE__");
7829#endif
7830#ifdef _MSC_VER
7831 ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
7832#endif
7833#ifdef _MSVC_LANG
7834 ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
7835#endif
7836#ifdef __MINGW32__
7837 ImGui::Text("define: __MINGW32__");
7838#endif
7839#ifdef __MINGW64__
7840 ImGui::Text("define: __MINGW64__");
7841#endif
7842#ifdef __GNUC__
7843 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
7844#endif
7845#ifdef __clang_version__
7846 ImGui::Text("define: __clang_version__=%s", __clang_version__);
7847#endif
7848#ifdef __EMSCRIPTEN__
7849 ImGui::Text("define: __EMSCRIPTEN__");
7850 ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
7851#endif
7852#ifdef IMGUI_HAS_VIEWPORT
7853 ImGui::Text("define: IMGUI_HAS_VIEWPORT");
7854#endif
7855#ifdef IMGUI_HAS_DOCK
7856 ImGui::Text("define: IMGUI_HAS_DOCK");
7857#endif
7858 ImGui::Separator();
7859 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
7860 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
7861 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
7862 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
7863 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
7864 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
7865 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
7866 if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard");
7867 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable");
7868 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable");
7869 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports");
7870 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts");
7871 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
7872 if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
7873 if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
7874 if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
7875 if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent");
7876 if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit");
7877 if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift");
7878 if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar");
7879 if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload");
7880 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
7881 if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos");
7882 if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard");
7883 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
7884 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
7885 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
7886 if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
7887 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
7888 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
7889 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
7890 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
7891 if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports");
7892 if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
7893 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
7894 if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports");
7895 ImGui::Separator();
7896 ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
7897 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
7898 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
7899 ImGui::Separator();
7900 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
7901 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
7902 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
7903 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
7904 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
7905 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
7906 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
7907
7908 if (copy_to_clipboard)
7909 {
7910 ImGui::LogText("\n```\n");
7911 ImGui::LogFinish();
7912 }
7913 ImGui::EndChild();
7914 }
7915 ImGui::End();
7916}
7917
7918//-----------------------------------------------------------------------------
7919// [SECTION] Style Editor / ShowStyleEditor()
7920//-----------------------------------------------------------------------------
7921// - ShowFontSelector()
7922// - ShowStyleSelector()
7923// - ShowStyleEditor()
7924//-----------------------------------------------------------------------------
7925
7926// Forward declare ShowFontAtlas() which isn't worth putting in public API yet
7927namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
7928
7929// Demo helper function to select among loaded fonts.
7930// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one.
7931void ImGui::ShowFontSelector(const char* label)
7932{
7933 ImGuiIO& io = ImGui::GetIO();
7934 ImFont* font_current = ImGui::GetFont();
7935 if (ImGui::BeginCombo(label, font_current->GetDebugName()))
7936 {
7937 for (ImFont* font : io.Fonts->Fonts)
7938 {
7939 ImGui::PushID((void*)font);
7940 if (ImGui::Selectable(font->GetDebugName(), font == font_current))
7941 io.FontDefault = font;
7942 ImGui::PopID();
7943 }
7944 ImGui::EndCombo();
7945 }
7946 ImGui::SameLine();
7947 HelpMarker(
7948 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
7949 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
7950 "- Read FAQ and docs/FONTS.md for more details.\n"
7951 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
7952}
7953
7954// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
7955// Here we use the simplified Combo() api that packs items into a single literal string.
7956// Useful for quick combo boxes where the choices are known locally.
7957bool ImGui::ShowStyleSelector(const char* label)
7958{
7959 static int style_idx = -1;
7960 if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0"))
7961 {
7962 switch (style_idx)
7963 {
7964 case 0: ImGui::StyleColorsDark(); break;
7965 case 1: ImGui::StyleColorsLight(); break;
7966 case 2: ImGui::StyleColorsClassic(); break;
7967 }
7968 return true;
7969 }
7970 return false;
7971}
7972
7973void ImGui::ShowStyleEditor(ImGuiStyle* ref)
7974{
7975 IMGUI_DEMO_MARKER("Tools/Style Editor");
7976 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
7977 // (without a reference style pointer, we will use one compared locally as a reference)
7978 ImGuiStyle& style = ImGui::GetStyle();
7979 static ImGuiStyle ref_saved_style;
7980
7981 // Default to using internal storage as reference
7982 static bool init = true;
7983 if (init && ref == NULL)
7984 ref_saved_style = style;
7985 init = false;
7986 if (ref == NULL)
7987 ref = &ref_saved_style;
7988
7989 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
7990
7991 if (ImGui::ShowStyleSelector("Colors##Selector"))
7992 ref_saved_style = style;
7993 ImGui::ShowFontSelector("Fonts##Selector");
7994
7995 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
7996 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
7997 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
7998 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
7999 ImGui::SameLine();
8000 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } }
8001 ImGui::SameLine();
8002 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } }
8003
8004 // Save/Revert button
8005 if (ImGui::Button("Save Ref"))
8006 *ref = ref_saved_style = style;
8007 ImGui::SameLine();
8008 if (ImGui::Button("Revert Ref"))
8009 style = *ref;
8010 ImGui::SameLine();
8011 HelpMarker(
8012 "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
8013 "Use \"Export\" below to save them somewhere.");
8014
8015 ImGui::Separator();
8016
8017 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
8018 {
8019 if (ImGui::BeginTabItem("Sizes"))
8020 {
8021 ImGui::SeparatorText("Main");
8022 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
8023 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
8024 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
8025 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
8026 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
8027 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
8028 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
8029 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
8030
8031 ImGui::SeparatorText("Borders");
8032 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
8033 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
8034 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
8035 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
8036 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
8037 ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
8038 ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f");
8039 ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
8040
8041 ImGui::SeparatorText("Rounding");
8042 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
8043 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
8044 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
8045 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
8046 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
8047 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
8048 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
8049
8050 ImGui::SeparatorText("Tables");
8051 ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
8052 ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
8053 ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f");
8054
8055 ImGui::SeparatorText("Widgets");
8056 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
8057 int window_menu_button_position = style.WindowMenuButtonPosition + 1;
8058 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
8059 style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
8060 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
8061 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
8062 ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
8063 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
8064 ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
8065 ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
8066 ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
8067 ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f");
8068 ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
8069
8070 ImGui::SeparatorText("Docking");
8071 ImGui::SliderFloat("DockingSplitterSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f");
8072
8073 ImGui::SeparatorText("Tooltips");
8074 for (int n = 0; n < 2; n++)
8075 if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
8076 {
8077 ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
8078 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone);
8079 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort);
8080 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal);
8081 ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary);
8082 ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay);
8083 ImGui::TreePop();
8084 }
8085
8086 ImGui::SeparatorText("Misc");
8087 ImGui::SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.");
8088 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
8089
8090 ImGui::EndTabItem();
8091 }
8092
8093 if (ImGui::BeginTabItem("Colors"))
8094 {
8095 static int output_dest = 0;
8096 static bool output_only_modified = true;
8097 if (ImGui::Button("Export"))
8098 {
8099 if (output_dest == 0)
8100 ImGui::LogToClipboard();
8101 else
8102 ImGui::LogToTTY();
8103 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
8104 for (int i = 0; i < ImGuiCol_COUNT; i++)
8105 {
8106 const ImVec4& col = style.Colors[i];
8107 const char* name = ImGui::GetStyleColorName(i);
8108 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
8109 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
8110 name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
8111 }
8112 ImGui::LogFinish();
8113 }
8114 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
8115 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
8116
8117 static ImGuiTextFilter filter;
8118 filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
8119
8120 static ImGuiColorEditFlags alpha_flags = 0;
8121 if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
8122 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
8123 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
8124 HelpMarker(
8125 "In the color list:\n"
8126 "Left-click on color square to open color picker,\n"
8127 "Right-click to open edit options menu.");
8128
8129 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
8130 ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
8131 ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
8132 for (int i = 0; i < ImGuiCol_COUNT; i++)
8133 {
8134 const char* name = ImGui::GetStyleColorName(i);
8135 if (!filter.PassFilter(name))
8136 continue;
8137 ImGui::PushID(i);
8138#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8139 if (ImGui::Button("?"))
8140 ImGui::DebugFlashStyleColor((ImGuiCol)i);
8141 ImGui::SetItemTooltip("Flash given color to identify places where it is used.");
8142 ImGui::SameLine();
8143#endif
8144 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
8145 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
8146 {
8147 // Tips: in a real user application, you may want to merge and use an icon font into the main font,
8148 // so instead of "Save"/"Revert" you'd use icons!
8149 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
8150 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
8151 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
8152 }
8153 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
8155 ImGui::PopID();
8156 }
8157 ImGui::PopItemWidth();
8158 ImGui::EndChild();
8159
8160 ImGui::EndTabItem();
8161 }
8162
8163 if (ImGui::BeginTabItem("Fonts"))
8164 {
8165 ImGuiIO& io = ImGui::GetIO();
8166 ImFontAtlas* atlas = io.Fonts;
8167 HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
8168 ImGui::ShowFontAtlas(atlas);
8169
8170 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
8171 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
8172 const float MIN_SCALE = 0.3f;
8173 const float MAX_SCALE = 2.0f;
8174 HelpMarker(
8175 "Those are old settings provided for convenience.\n"
8176 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
8177 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
8178 "Using those settings here will give you poor quality results.");
8179 static float window_scale = 1.0f;
8180 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8181 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
8182 ImGui::SetWindowFontScale(window_scale);
8183 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
8184 ImGui::PopItemWidth();
8185
8186 ImGui::EndTabItem();
8187 }
8188
8189 if (ImGui::BeginTabItem("Rendering"))
8190 {
8191 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
8192 ImGui::SameLine();
8193 HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
8194
8195 ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
8196 ImGui::SameLine();
8197 HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
8198
8199 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
8200 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
8201 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
8202 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
8203
8204 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
8205 ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
8206 const bool show_samples = ImGui::IsItemActive();
8207 if (show_samples)
8208 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
8209 if (show_samples && ImGui::BeginTooltip())
8210 {
8211 ImGui::TextUnformatted("(R = radius, N = approx number of segments)");
8212 ImGui::Spacing();
8213 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8214 const float min_widget_width = ImGui::CalcTextSize("R: MMM\nN: MMM").x;
8215 for (int n = 0; n < 8; n++)
8216 {
8217 const float RAD_MIN = 5.0f;
8218 const float RAD_MAX = 70.0f;
8219 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
8220
8221 ImGui::BeginGroup();
8222
8223 // N is not always exact here due to how PathArcTo() function work internally
8224 ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
8225
8226 const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
8227 const float offset_x = floorf(canvas_width * 0.5f);
8228 const float offset_y = floorf(RAD_MAX);
8229
8230 const ImVec2 p1 = ImGui::GetCursorScreenPos();
8231 draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8232 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8233
8234 /*
8235 const ImVec2 p2 = ImGui::GetCursorScreenPos();
8236 draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
8237 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
8238 */
8239
8240 ImGui::EndGroup();
8241 ImGui::SameLine();
8242 }
8243 ImGui::EndTooltip();
8244 }
8245 ImGui::SameLine();
8246 HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
8247
8248 ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
8249 ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).");
8250 ImGui::PopItemWidth();
8251
8252 ImGui::EndTabItem();
8253 }
8254
8255 ImGui::EndTabBar();
8256 }
8257
8258 ImGui::PopItemWidth();
8259}
8260
8261//-----------------------------------------------------------------------------
8262// [SECTION] User Guide / ShowUserGuide()
8263//-----------------------------------------------------------------------------
8264
8265void ImGui::ShowUserGuide()
8266{
8267 ImGuiIO& io = ImGui::GetIO();
8268 ImGui::BulletText("Double-click on title bar to collapse window.");
8269 ImGui::BulletText(
8270 "Click and drag on lower corner to resize window\n"
8271 "(double-click to auto fit window to its contents).");
8272 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
8273 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
8274 ImGui::BulletText("CTRL+Tab to select a window.");
8275 if (io.FontAllowUserScaling)
8276 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
8277 ImGui::BulletText("While inputing text:\n");
8278 ImGui::Indent();
8279 ImGui::BulletText("CTRL+Left/Right to word jump.");
8280 ImGui::BulletText("CTRL+A or double-click to select all.");
8281 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
8282 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
8283 ImGui::BulletText("ESCAPE to revert.");
8284 ImGui::Unindent();
8285 ImGui::BulletText("With keyboard navigation enabled:");
8286 ImGui::Indent();
8287 ImGui::BulletText("Arrow keys to navigate.");
8288 ImGui::BulletText("Space to activate a widget.");
8289 ImGui::BulletText("Return to input text into a widget.");
8290 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
8291 ImGui::BulletText("Alt to jump to the menu layer of a window.");
8292 ImGui::Unindent();
8293}
8294
8295//-----------------------------------------------------------------------------
8296// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
8297//-----------------------------------------------------------------------------
8298// - ShowExampleAppMainMenuBar()
8299// - ShowExampleMenuFile()
8300//-----------------------------------------------------------------------------
8301
8302// Demonstrate creating a "main" fullscreen menu bar and populating it.
8303// Note the difference between BeginMainMenuBar() and BeginMenuBar():
8304// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
8305// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
8306static void ShowExampleAppMainMenuBar()
8307{
8308 if (ImGui::BeginMainMenuBar())
8309 {
8310 if (ImGui::BeginMenu("File"))
8311 {
8312 ShowExampleMenuFile();
8313 ImGui::EndMenu();
8314 }
8315 if (ImGui::BeginMenu("Edit"))
8316 {
8317 if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
8318 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
8319 ImGui::Separator();
8320 if (ImGui::MenuItem("Cut", "CTRL+X")) {}
8321 if (ImGui::MenuItem("Copy", "CTRL+C")) {}
8322 if (ImGui::MenuItem("Paste", "CTRL+V")) {}
8323 ImGui::EndMenu();
8324 }
8325 ImGui::EndMainMenuBar();
8326 }
8327}
8328
8329// Note that shortcuts are currently provided for display only
8330// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
8331static void ShowExampleMenuFile()
8332{
8333 IMGUI_DEMO_MARKER("Examples/Menu");
8334 ImGui::MenuItem("(demo menu)", NULL, false, false);
8335 if (ImGui::MenuItem("New")) {}
8336 if (ImGui::MenuItem("Open", "Ctrl+O")) {}
8337 if (ImGui::BeginMenu("Open Recent"))
8338 {
8339 ImGui::MenuItem("fish_hat.c");
8340 ImGui::MenuItem("fish_hat.inl");
8341 ImGui::MenuItem("fish_hat.h");
8342 if (ImGui::BeginMenu("More.."))
8343 {
8344 ImGui::MenuItem("Hello");
8345 ImGui::MenuItem("Sailor");
8346 if (ImGui::BeginMenu("Recurse.."))
8347 {
8348 ShowExampleMenuFile();
8349 ImGui::EndMenu();
8350 }
8351 ImGui::EndMenu();
8352 }
8353 ImGui::EndMenu();
8354 }
8355 if (ImGui::MenuItem("Save", "Ctrl+S")) {}
8356 if (ImGui::MenuItem("Save As..")) {}
8357
8358 ImGui::Separator();
8359 IMGUI_DEMO_MARKER("Examples/Menu/Options");
8360 if (ImGui::BeginMenu("Options"))
8361 {
8362 static bool enabled = true;
8363 ImGui::MenuItem("Enabled", "", &enabled);
8364 ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders);
8365 for (int i = 0; i < 10; i++)
8366 ImGui::Text("Scrolling Text %d", i);
8367 ImGui::EndChild();
8368 static float f = 0.5f;
8369 static int n = 0;
8370 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
8371 ImGui::InputFloat("Input", &f, 0.1f);
8372 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
8373 ImGui::EndMenu();
8374 }
8375
8376 IMGUI_DEMO_MARKER("Examples/Menu/Colors");
8377 if (ImGui::BeginMenu("Colors"))
8378 {
8379 float sz = ImGui::GetTextLineHeight();
8380 for (int i = 0; i < ImGuiCol_COUNT; i++)
8381 {
8382 const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
8383 ImVec2 p = ImGui::GetCursorScreenPos();
8384 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
8385 ImGui::Dummy(ImVec2(sz, sz));
8386 ImGui::SameLine();
8387 ImGui::MenuItem(name);
8388 }
8389 ImGui::EndMenu();
8390 }
8391
8392 // Here we demonstrate appending again to the "Options" menu (which we already created above)
8393 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
8394 // In a real code-base using it would make senses to use this feature from very different code locations.
8395 if (ImGui::BeginMenu("Options")) // <-- Append!
8396 {
8397 IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
8398 static bool b = true;
8399 ImGui::Checkbox("SomeOption", &b);
8400 ImGui::EndMenu();
8401 }
8402
8403 if (ImGui::BeginMenu("Disabled", false)) // Disabled
8404 {
8405 IM_ASSERT(0);
8406 }
8407 if (ImGui::MenuItem("Checked", NULL, true)) {}
8408 ImGui::Separator();
8409 if (ImGui::MenuItem("Quit", "Alt+F4")) {}
8410}
8411
8412//-----------------------------------------------------------------------------
8413// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
8414//-----------------------------------------------------------------------------
8415
8416// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
8417// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
8419{
8420 char InputBuf[256];
8421 ImVector<char*> Items;
8422 ImVector<const char*> Commands;
8423 ImVector<char*> History;
8424 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
8425 ImGuiTextFilter Filter;
8428
8430 {
8431 IMGUI_DEMO_MARKER("Examples/Console");
8432 ClearLog();
8433 memset(InputBuf, 0, sizeof(InputBuf));
8434 HistoryPos = -1;
8435
8436 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
8437 Commands.push_back("HELP");
8438 Commands.push_back("HISTORY");
8439 Commands.push_back("CLEAR");
8440 Commands.push_back("CLASSIFY");
8441 AutoScroll = true;
8442 ScrollToBottom = false;
8443 AddLog("Welcome to Dear ImGui!");
8444 }
8446 {
8447 ClearLog();
8448 for (int i = 0; i < History.Size; i++)
8449 ImGui::MemFree(History[i]);
8450 }
8451
8452 // Portable helpers
8453 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
8454 static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; }
8455 static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = ImGui::MemAlloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
8456 static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
8457
8459 {
8460 for (int i = 0; i < Items.Size; i++)
8461 ImGui::MemFree(Items[i]);
8462 Items.clear();
8463 }
8464
8465 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
8466 {
8467 // FIXME-OPT
8468 char buf[1024];
8469 va_list args;
8470 va_start(args, fmt);
8471 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
8472 buf[IM_ARRAYSIZE(buf)-1] = 0;
8473 va_end(args);
8474 Items.push_back(Strdup(buf));
8475 }
8476
8477 void Draw(const char* title, bool* p_open)
8478 {
8479 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
8480 if (!ImGui::Begin(title, p_open))
8481 {
8482 ImGui::End();
8483 return;
8484 }
8485
8486 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
8487 // So e.g. IsItemHovered() will return true when hovering the title bar.
8488 // Here we create a context menu only available from the title bar.
8489 if (ImGui::BeginPopupContextItem())
8490 {
8491 if (ImGui::MenuItem("Close Console"))
8492 *p_open = false;
8493 ImGui::EndPopup();
8494 }
8495
8496 ImGui::TextWrapped(
8497 "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
8498 "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
8499 ImGui::TextWrapped("Enter 'HELP' for help.");
8500
8501 // TODO: display items starting from the bottom
8502
8503 if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
8504 ImGui::SameLine();
8505 if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
8506 ImGui::SameLine();
8507 if (ImGui::SmallButton("Clear")) { ClearLog(); }
8508 ImGui::SameLine();
8509 bool copy_to_clipboard = ImGui::SmallButton("Copy");
8510 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
8511
8512 ImGui::Separator();
8513
8514 // Options menu
8515 if (ImGui::BeginPopup("Options"))
8516 {
8517 ImGui::Checkbox("Auto-scroll", &AutoScroll);
8518 ImGui::EndPopup();
8519 }
8520
8521 // Options, Filter
8522 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_O, ImGuiInputFlags_Tooltip);
8523 if (ImGui::Button("Options"))
8524 ImGui::OpenPopup("Options");
8525 ImGui::SameLine();
8526 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
8527 ImGui::Separator();
8528
8529 // Reserve enough left-over height for 1 separator + 1 input text
8530 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
8531 if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
8532 {
8533 if (ImGui::BeginPopupContextWindow())
8534 {
8535 if (ImGui::Selectable("Clear")) ClearLog();
8536 ImGui::EndPopup();
8537 }
8538
8539 // Display every line as a separate entry so we can change their color or add custom widgets.
8540 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
8541 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
8542 // to only process visible items. The clipper will automatically measure the height of your first item and then
8543 // "seek" to display only items in the visible area.
8544 // To use the clipper we can replace your standard loop:
8545 // for (int i = 0; i < Items.Size; i++)
8546 // With:
8547 // ImGuiListClipper clipper;
8548 // clipper.Begin(Items.Size);
8549 // while (clipper.Step())
8550 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
8551 // - That your items are evenly spaced (same height)
8552 // - That you have cheap random access to your elements (you can access them given their index,
8553 // without processing all the ones before)
8554 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
8555 // We would need random-access on the post-filtered list.
8556 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
8557 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
8558 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
8559 // to improve this example code!
8560 // If your items are of variable height:
8561 // - Split them into same height items would be simpler and facilitate random-seeking into your list.
8562 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
8563 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
8564 if (copy_to_clipboard)
8565 ImGui::LogToClipboard();
8566 for (const char* item : Items)
8567 {
8568 if (!Filter.PassFilter(item))
8569 continue;
8570
8571 // Normally you would store more information in your item than just a string.
8572 // (e.g. make Items[] an array of structure, store color/type etc.)
8573 ImVec4 color;
8574 bool has_color = false;
8575 if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
8576 else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
8577 if (has_color)
8578 ImGui::PushStyleColor(ImGuiCol_Text, color);
8580 if (has_color)
8581 ImGui::PopStyleColor();
8582 }
8583 if (copy_to_clipboard)
8584 ImGui::LogFinish();
8585
8586 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8587 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
8588 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
8589 ImGui::SetScrollHereY(1.0f);
8590 ScrollToBottom = false;
8591
8592 ImGui::PopStyleVar();
8593 }
8594 ImGui::EndChild();
8595 ImGui::Separator();
8596
8597 // Command-line
8598 bool reclaim_focus = false;
8599 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
8600 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
8601 {
8602 char* s = InputBuf;
8603 Strtrim(s);
8604 if (s[0])
8605 ExecCommand(s);
8606 strcpy(s, "");
8607 reclaim_focus = true;
8608 }
8609
8610 // Auto-focus on window apparition
8611 ImGui::SetItemDefaultFocus();
8612 if (reclaim_focus)
8613 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
8614
8615 ImGui::End();
8616 }
8617
8618 void ExecCommand(const char* command_line)
8619 {
8620 AddLog("# %s\n", command_line);
8621
8622 // Insert into history. First find match and delete it so it can be pushed to the back.
8623 // This isn't trying to be smart or optimal.
8624 HistoryPos = -1;
8625 for (int i = History.Size - 1; i >= 0; i--)
8626 if (Stricmp(History[i], command_line) == 0)
8627 {
8628 ImGui::MemFree(History[i]);
8629 History.erase(History.begin() + i);
8630 break;
8631 }
8632 History.push_back(Strdup(command_line));
8633
8634 // Process command
8635 if (Stricmp(command_line, "CLEAR") == 0)
8636 {
8637 ClearLog();
8638 }
8639 else if (Stricmp(command_line, "HELP") == 0)
8640 {
8641 AddLog("Commands:");
8642 for (int i = 0; i < Commands.Size; i++)
8643 AddLog("- %s", Commands[i]);
8644 }
8645 else if (Stricmp(command_line, "HISTORY") == 0)
8646 {
8647 int first = History.Size - 10;
8648 for (int i = first > 0 ? first : 0; i < History.Size; i++)
8649 AddLog("%3d: %s\n", i, History[i]);
8650 }
8651 else
8652 {
8653 AddLog("Unknown command: '%s'\n", command_line);
8654 }
8655
8656 // On command input, we scroll to bottom even if AutoScroll==false
8657 ScrollToBottom = true;
8658 }
8659
8660 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
8661 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
8662 {
8663 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
8664 return console->TextEditCallback(data);
8665 }
8666
8667 int TextEditCallback(ImGuiInputTextCallbackData* data)
8668 {
8669 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
8670 switch (data->EventFlag)
8671 {
8672 case ImGuiInputTextFlags_CallbackCompletion:
8673 {
8674 // Example of TEXT COMPLETION
8675
8676 // Locate beginning of current word
8677 const char* word_end = data->Buf + data->CursorPos;
8678 const char* word_start = word_end;
8679 while (word_start > data->Buf)
8680 {
8681 const char c = word_start[-1];
8682 if (c == ' ' || c == '\t' || c == ',' || c == ';')
8683 break;
8684 word_start--;
8685 }
8686
8687 // Build a list of candidates
8688 ImVector<const char*> candidates;
8689 for (int i = 0; i < Commands.Size; i++)
8690 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
8691 candidates.push_back(Commands[i]);
8692
8693 if (candidates.Size == 0)
8694 {
8695 // No match
8696 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
8697 }
8698 else if (candidates.Size == 1)
8699 {
8700 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
8701 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8702 data->InsertChars(data->CursorPos, candidates[0]);
8703 data->InsertChars(data->CursorPos, " ");
8704 }
8705 else
8706 {
8707 // Multiple matches. Complete as much as we can..
8708 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
8709 int match_len = (int)(word_end - word_start);
8710 for (;;)
8711 {
8712 int c = 0;
8713 bool all_candidates_matches = true;
8714 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
8715 if (i == 0)
8716 c = toupper(candidates[i][match_len]);
8717 else if (c == 0 || c != toupper(candidates[i][match_len]))
8718 all_candidates_matches = false;
8719 if (!all_candidates_matches)
8720 break;
8721 match_len++;
8722 }
8723
8724 if (match_len > 0)
8725 {
8726 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
8727 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
8728 }
8729
8730 // List matches
8731 AddLog("Possible matches:\n");
8732 for (int i = 0; i < candidates.Size; i++)
8733 AddLog("- %s\n", candidates[i]);
8734 }
8735
8736 break;
8737 }
8738 case ImGuiInputTextFlags_CallbackHistory:
8739 {
8740 // Example of HISTORY
8741 const int prev_history_pos = HistoryPos;
8742 if (data->EventKey == ImGuiKey_UpArrow)
8743 {
8744 if (HistoryPos == -1)
8745 HistoryPos = History.Size - 1;
8746 else if (HistoryPos > 0)
8747 HistoryPos--;
8748 }
8749 else if (data->EventKey == ImGuiKey_DownArrow)
8750 {
8751 if (HistoryPos != -1)
8752 if (++HistoryPos >= History.Size)
8753 HistoryPos = -1;
8754 }
8755
8756 // A better implementation would preserve the data on the current input line along with cursor position.
8757 if (prev_history_pos != HistoryPos)
8758 {
8759 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
8760 data->DeleteChars(0, data->BufTextLen);
8761 data->InsertChars(0, history_str);
8762 }
8763 }
8764 }
8765 return 0;
8766 }
8767};
8768
8769static void ShowExampleAppConsole(bool* p_open)
8770{
8771 static ExampleAppConsole console;
8772 console.Draw("Example: Console", p_open);
8773}
8774
8775//-----------------------------------------------------------------------------
8776// [SECTION] Example App: Debug Log / ShowExampleAppLog()
8777//-----------------------------------------------------------------------------
8778
8779// Usage:
8780// static ExampleAppLog my_log;
8781// my_log.AddLog("Hello %d world\n", 123);
8782// my_log.Draw("title");
8784{
8785 ImGuiTextBuffer Buf;
8786 ImGuiTextFilter Filter;
8787 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
8788 bool AutoScroll; // Keep scrolling if already at the bottom.
8789
8791 {
8792 AutoScroll = true;
8793 Clear();
8794 }
8795
8796 void Clear()
8797 {
8798 Buf.clear();
8799 LineOffsets.clear();
8800 LineOffsets.push_back(0);
8801 }
8802
8803 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
8804 {
8805 int old_size = Buf.size();
8806 va_list args;
8807 va_start(args, fmt);
8808 Buf.appendfv(fmt, args);
8809 va_end(args);
8810 for (int new_size = Buf.size(); old_size < new_size; old_size++)
8811 if (Buf[old_size] == '\n')
8812 LineOffsets.push_back(old_size + 1);
8813 }
8814
8815 void Draw(const char* title, bool* p_open = NULL)
8816 {
8817 if (!ImGui::Begin(title, p_open))
8818 {
8819 ImGui::End();
8820 return;
8821 }
8822
8823 // Options menu
8824 if (ImGui::BeginPopup("Options"))
8825 {
8826 ImGui::Checkbox("Auto-scroll", &AutoScroll);
8827 ImGui::EndPopup();
8828 }
8829
8830 // Main window
8831 if (ImGui::Button("Options"))
8832 ImGui::OpenPopup("Options");
8833 ImGui::SameLine();
8834 bool clear = ImGui::Button("Clear");
8835 ImGui::SameLine();
8836 bool copy = ImGui::Button("Copy");
8837 ImGui::SameLine();
8838 Filter.Draw("Filter", -100.0f);
8839
8840 ImGui::Separator();
8841
8842 if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
8843 {
8844 if (clear)
8845 Clear();
8846 if (copy)
8847 ImGui::LogToClipboard();
8848
8849 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
8850 const char* buf = Buf.begin();
8851 const char* buf_end = Buf.end();
8852 if (Filter.IsActive())
8853 {
8854 // In this example we don't use the clipper when Filter is enabled.
8855 // This is because we don't have random access to the result of our filter.
8856 // A real application processing logs with ten of thousands of entries may want to store the result of
8857 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
8858 for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
8859 {
8860 const char* line_start = buf + LineOffsets[line_no];
8861 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8862 if (Filter.PassFilter(line_start, line_end))
8863 ImGui::TextUnformatted(line_start, line_end);
8864 }
8865 }
8866 else
8867 {
8868 // The simplest and easy way to display the entire buffer:
8869 // ImGui::TextUnformatted(buf_begin, buf_end);
8870 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
8871 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
8872 // within the visible area.
8873 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
8874 // on your side is recommended. Using ImGuiListClipper requires
8875 // - A) random access into your data
8876 // - B) items all being the same height,
8877 // both of which we can handle since we have an array pointing to the beginning of each line of text.
8878 // When using the filter (in the block of code above) we don't have random access into the data to display
8879 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
8880 // it possible (and would be recommended if you want to search through tens of thousands of entries).
8881 ImGuiListClipper clipper;
8882 clipper.Begin(LineOffsets.Size);
8883 while (clipper.Step())
8884 {
8885 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
8886 {
8887 const char* line_start = buf + LineOffsets[line_no];
8888 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
8889 ImGui::TextUnformatted(line_start, line_end);
8890 }
8891 }
8892 clipper.End();
8893 }
8894 ImGui::PopStyleVar();
8895
8896 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
8897 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
8898 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
8899 ImGui::SetScrollHereY(1.0f);
8900 }
8901 ImGui::EndChild();
8902 ImGui::End();
8903 }
8904};
8905
8906// Demonstrate creating a simple log window with basic filtering.
8907static void ShowExampleAppLog(bool* p_open)
8908{
8909 static ExampleAppLog log;
8910
8911 // For the demo: add a debug button _BEFORE_ the normal log window contents
8912 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
8913 // Most of the contents of the window will be added by the log.Draw() call.
8914 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
8915 ImGui::Begin("Example: Log", p_open);
8916 IMGUI_DEMO_MARKER("Examples/Log");
8917 if (ImGui::SmallButton("[Debug] Add 5 entries"))
8918 {
8919 static int counter = 0;
8920 const char* categories[3] = { "info", "warn", "error" };
8921 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
8922 for (int n = 0; n < 5; n++)
8923 {
8924 const char* category = categories[counter % IM_ARRAYSIZE(categories)];
8925 const char* word = words[counter % IM_ARRAYSIZE(words)];
8926 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
8927 ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
8928 counter++;
8929 }
8930 }
8931 ImGui::End();
8932
8933 // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
8934 log.Draw("Example: Log", p_open);
8935}
8936
8937//-----------------------------------------------------------------------------
8938// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
8939//-----------------------------------------------------------------------------
8940
8941// Demonstrate create a window with multiple child windows.
8942static void ShowExampleAppLayout(bool* p_open)
8943{
8944 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
8945 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
8946 {
8947 IMGUI_DEMO_MARKER("Examples/Simple layout");
8948 if (ImGui::BeginMenuBar())
8949 {
8950 if (ImGui::BeginMenu("File"))
8951 {
8952 if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; }
8953 ImGui::EndMenu();
8954 }
8955 ImGui::EndMenuBar();
8956 }
8957
8958 // Left
8959 static int selected = 0;
8960 {
8961 ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
8962 for (int i = 0; i < 100; i++)
8963 {
8964 // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
8965 char label[128];
8966 sprintf(label, "MyObject %d", i);
8967 if (ImGui::Selectable(label, selected == i))
8968 selected = i;
8969 }
8970 ImGui::EndChild();
8971 }
8972 ImGui::SameLine();
8973
8974 // Right
8975 {
8976 ImGui::BeginGroup();
8977 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
8978 ImGui::Text("MyObject: %d", selected);
8979 ImGui::Separator();
8980 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
8981 {
8982 if (ImGui::BeginTabItem("Description"))
8983 {
8984 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
8985 ImGui::EndTabItem();
8986 }
8987 if (ImGui::BeginTabItem("Details"))
8988 {
8989 ImGui::Text("ID: 0123456789");
8990 ImGui::EndTabItem();
8991 }
8992 ImGui::EndTabBar();
8993 }
8994 ImGui::EndChild();
8995 if (ImGui::Button("Revert")) {}
8996 ImGui::SameLine();
8997 if (ImGui::Button("Save")) {}
8998 ImGui::EndGroup();
8999 }
9000 }
9001 ImGui::End();
9002}
9003
9004//-----------------------------------------------------------------------------
9005// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
9006//-----------------------------------------------------------------------------
9007// Some of the interactions are a bit lack-luster:
9008// - We would want pressing validating or leaving the filter to somehow restore focus.
9009// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
9010// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
9011//-----------------------------------------------------------------------------
9012
9014{
9015 ImGuiTextFilter Filter;
9017
9018 void Draw(ExampleTreeNode* root_node)
9019 {
9020 // Left side: draw tree
9021 // - Currently using a table to benefit from RowBg feature
9022 if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
9023 {
9024 ImGui::SetNextItemWidth(-FLT_MIN);
9025 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
9026 ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
9027 if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
9028 Filter.Build();
9029 ImGui::PopItemFlag();
9030
9031 if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg))
9032 {
9033 for (ExampleTreeNode* node : root_node->Childs)
9034 if (Filter.PassFilter(node->Name)) // Filter root node
9035 DrawTreeNode(node);
9036 ImGui::EndTable();
9037 }
9038 }
9039 ImGui::EndChild();
9040
9041 // Right side: draw properties
9042 ImGui::SameLine();
9043
9044 ImGui::BeginGroup(); // Lock X position
9045 if (ExampleTreeNode* node = VisibleNode)
9046 {
9047 ImGui::Text("%s", node->Name);
9048 ImGui::TextDisabled("UID: 0x%08X", node->UID);
9049 ImGui::Separator();
9050 if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
9051 {
9052 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
9053 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
9054 if (node->HasData)
9055 {
9056 // In a typical application, the structure description would be derived from a data-driven system.
9057 // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
9058 // - Limits and some details are hard-coded to simplify the demo.
9059 for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
9060 {
9061 ImGui::TableNextRow();
9062 ImGui::PushID(field_desc.Name);
9063 ImGui::TableNextColumn();
9064 ImGui::AlignTextToFramePadding();
9065 ImGui::TextUnformatted(field_desc.Name);
9066 ImGui::TableNextColumn();
9067 void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
9068 switch (field_desc.DataType)
9069 {
9070 case ImGuiDataType_Bool:
9071 {
9072 IM_ASSERT(field_desc.DataCount == 1);
9073 ImGui::Checkbox("##Editor", (bool*)field_ptr);
9074 break;
9075 }
9076 case ImGuiDataType_S32:
9077 {
9078 int v_min = INT_MIN, v_max = INT_MAX;
9079 ImGui::SetNextItemWidth(-FLT_MIN);
9080 ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
9081 break;
9082 }
9083 case ImGuiDataType_Float:
9084 {
9085 float v_min = 0.0f, v_max = 1.0f;
9086 ImGui::SetNextItemWidth(-FLT_MIN);
9087 ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
9088 break;
9089 }
9090 }
9091 ImGui::PopID();
9092 }
9093 }
9094 ImGui::EndTable();
9095 }
9096 }
9097 ImGui::EndGroup();
9098 }
9099
9101 {
9102 ImGui::TableNextRow();
9103 ImGui::TableNextColumn();
9104 ImGui::PushID(node->UID);
9105 ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
9106 tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
9107 tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
9108 if (node == VisibleNode)
9109 tree_flags |= ImGuiTreeNodeFlags_Selected;
9110 if (node->Childs.Size == 0)
9111 tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
9112 if (node->DataMyBool == false)
9113 ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
9114 bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
9115 if (node->DataMyBool == false)
9116 ImGui::PopStyleColor();
9117 if (ImGui::IsItemFocused())
9118 VisibleNode = node;
9119 if (node_open)
9120 {
9121 for (ExampleTreeNode* child : node->Childs)
9122 DrawTreeNode(child);
9123 ImGui::TreePop();
9124 }
9125 ImGui::PopID();
9126 }
9127};
9128
9129// Demonstrate creating a simple property editor.
9130static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data)
9131{
9132 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
9133 if (!ImGui::Begin("Example: Property editor", p_open))
9134 {
9135 ImGui::End();
9136 return;
9137 }
9138
9139 IMGUI_DEMO_MARKER("Examples/Property Editor");
9140 static ExampleAppPropertyEditor property_editor;
9141 if (demo_data->DemoTree == NULL)
9142 demo_data->DemoTree = ExampleTree_CreateDemoTree();
9143 property_editor.Draw(demo_data->DemoTree);
9144
9145 ImGui::End();
9146}
9147
9148//-----------------------------------------------------------------------------
9149// [SECTION] Example App: Long Text / ShowExampleAppLongText()
9150//-----------------------------------------------------------------------------
9151
9152// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
9153static void ShowExampleAppLongText(bool* p_open)
9154{
9155 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
9156 if (!ImGui::Begin("Example: Long text display", p_open))
9157 {
9158 ImGui::End();
9159 return;
9160 }
9161 IMGUI_DEMO_MARKER("Examples/Long text display");
9162
9163 static int test_type = 0;
9164 static ImGuiTextBuffer log;
9165 static int lines = 0;
9166 ImGui::Text("Printing unusually long amount of text.");
9167 ImGui::Combo("Test type", &test_type,
9168 "Single call to TextUnformatted()\0"
9169 "Multiple calls to Text(), clipped\0"
9170 "Multiple calls to Text(), not clipped (slow)\0");
9171 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
9172 if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
9173 ImGui::SameLine();
9174 if (ImGui::Button("Add 1000 lines"))
9175 {
9176 for (int i = 0; i < 1000; i++)
9177 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
9178 lines += 1000;
9179 }
9180 ImGui::BeginChild("Log");
9181 switch (test_type)
9182 {
9183 case 0:
9184 // Single call to TextUnformatted() with a big buffer
9185 ImGui::TextUnformatted(log.begin(), log.end());
9186 break;
9187 case 1:
9188 {
9189 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
9190 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9191 ImGuiListClipper clipper;
9192 clipper.Begin(lines);
9193 while (clipper.Step())
9194 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
9195 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9196 ImGui::PopStyleVar();
9197 break;
9198 }
9199 case 2:
9200 // Multiple calls to Text(), not clipped (slow)
9201 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
9202 for (int i = 0; i < lines; i++)
9203 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
9204 ImGui::PopStyleVar();
9205 break;
9206 }
9207 ImGui::EndChild();
9208 ImGui::End();
9209}
9210
9211//-----------------------------------------------------------------------------
9212// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
9213//-----------------------------------------------------------------------------
9214
9215// Demonstrate creating a window which gets auto-resized according to its content.
9216static void ShowExampleAppAutoResize(bool* p_open)
9217{
9218 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
9219 {
9220 ImGui::End();
9221 return;
9222 }
9223 IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
9224
9225 static int lines = 10;
9227 "Window will resize every-frame to the size of its content.\n"
9228 "Note that you probably don't want to query the window size to\n"
9229 "output your content because that would create a feedback loop.");
9230 ImGui::SliderInt("Number of lines", &lines, 1, 20);
9231 for (int i = 0; i < lines; i++)
9232 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
9233 ImGui::End();
9234}
9235
9236//-----------------------------------------------------------------------------
9237// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
9238//-----------------------------------------------------------------------------
9239
9240// Demonstrate creating a window with custom resize constraints.
9241// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
9242static void ShowExampleAppConstrainedResize(bool* p_open)
9243{
9244 struct CustomConstraints
9245 {
9246 // Helper functions to demonstrate programmatic constraints
9247 // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
9248 // FIXME: None of the three demos works consistently when resizing from borders.
9249 static void AspectRatio(ImGuiSizeCallbackData* data)
9250 {
9251 float aspect_ratio = *(float*)data->UserData;
9252 data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
9253 }
9254 static void Square(ImGuiSizeCallbackData* data)
9255 {
9256 data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
9257 }
9258 static void Step(ImGuiSizeCallbackData* data)
9259 {
9260 float step = *(float*)data->UserData;
9261 data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
9262 }
9263 };
9264
9265 const char* test_desc[] =
9266 {
9267 "Between 100x100 and 500x500",
9268 "At least 100x100",
9269 "Resize vertical + lock current width",
9270 "Resize horizontal + lock current height",
9271 "Width Between 400 and 500",
9272 "Height at least 400",
9273 "Custom: Aspect Ratio 16:9",
9274 "Custom: Always Square",
9275 "Custom: Fixed Steps (100)",
9276 };
9277
9278 // Options
9279 static bool auto_resize = false;
9280 static bool window_padding = true;
9281 static int type = 6; // Aspect Ratio
9282 static int display_lines = 10;
9283
9284 // Submit constraint
9285 float aspect_ratio = 16.0f / 9.0f;
9286 float fixed_step = 100.0f;
9287 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500
9288 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
9289 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width
9290 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height
9291 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500
9292 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, FLT_MAX)); // Height at least 400
9293 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio
9294 if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
9295 if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step
9296
9297 // Submit window
9298 if (!window_padding)
9299 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9300 const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
9301 const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
9302 if (!window_padding)
9303 ImGui::PopStyleVar();
9304 if (window_open)
9305 {
9306 IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
9307 if (ImGui::GetIO().KeyShift)
9308 {
9309 // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture.
9310 ImVec2 avail_size = ImGui::GetContentRegionAvail();
9311 ImVec2 pos = ImGui::GetCursorScreenPos();
9312 ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
9313 ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
9314 ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
9315 }
9316 else
9317 {
9318 ImGui::Text("(Hold SHIFT to display a dummy viewport)");
9319 if (ImGui::IsWindowDocked())
9320 ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
9321 if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
9322 if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
9323 if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
9324 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9325 ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
9326 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
9327 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
9328 ImGui::Checkbox("Auto-resize", &auto_resize);
9329 ImGui::Checkbox("Window padding", &window_padding);
9330 for (int i = 0; i < display_lines; i++)
9331 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
9332 }
9333 }
9334 ImGui::End();
9335}
9336
9337//-----------------------------------------------------------------------------
9338// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
9339//-----------------------------------------------------------------------------
9340
9341// Demonstrate creating a simple static window with no decoration
9342// + a context-menu to choose which corner of the screen to use.
9343static void ShowExampleAppSimpleOverlay(bool* p_open)
9344{
9345 static int location = 0;
9346 ImGuiIO& io = ImGui::GetIO();
9347 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
9348 if (location >= 0)
9349 {
9350 const float PAD = 10.0f;
9351 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9352 ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
9353 ImVec2 work_size = viewport->WorkSize;
9354 ImVec2 window_pos, window_pos_pivot;
9355 window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
9356 window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
9357 window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
9358 window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
9359 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
9360 ImGui::SetNextWindowViewport(viewport->ID);
9361 window_flags |= ImGuiWindowFlags_NoMove;
9362 }
9363 else if (location == -2)
9364 {
9365 // Center window
9366 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
9367 window_flags |= ImGuiWindowFlags_NoMove;
9368 }
9369 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
9370 if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
9371 {
9372 IMGUI_DEMO_MARKER("Examples/Simple Overlay");
9373 ImGui::Text("Simple overlay\n" "(right-click to change position)");
9374 ImGui::Separator();
9375 if (ImGui::IsMousePosValid())
9376 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
9377 else
9378 ImGui::Text("Mouse Position: <invalid>");
9379 if (ImGui::BeginPopupContextWindow())
9380 {
9381 if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1;
9382 if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2;
9383 if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0;
9384 if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1;
9385 if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2;
9386 if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
9387 if (p_open && ImGui::MenuItem("Close")) *p_open = false;
9388 ImGui::EndPopup();
9389 }
9390 }
9391 ImGui::End();
9392}
9393
9394//-----------------------------------------------------------------------------
9395// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
9396//-----------------------------------------------------------------------------
9397
9398// Demonstrate creating a window covering the entire screen/viewport
9399static void ShowExampleAppFullscreen(bool* p_open)
9400{
9401 static bool use_work_area = true;
9402 static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
9403
9404 // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
9405 // Based on your use case you may want one or the other.
9406 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9407 ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
9408 ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
9409
9410 if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
9411 {
9412 ImGui::Checkbox("Use work area instead of main area", &use_work_area);
9413 ImGui::SameLine();
9414 HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.");
9415
9416 ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
9417 ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
9418 ImGui::Indent();
9419 ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
9420 ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
9421 ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
9422 ImGui::Unindent();
9423
9424 if (p_open && ImGui::Button("Close this window"))
9425 *p_open = false;
9426 }
9427 ImGui::End();
9428}
9429
9430//-----------------------------------------------------------------------------
9431// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
9432//-----------------------------------------------------------------------------
9433
9434// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
9435// This applies to all regular items as well.
9436// Read FAQ section "How can I have multiple widgets with the same label?" for details.
9437static void ShowExampleAppWindowTitles(bool*)
9438{
9439 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9440 const ImVec2 base_pos = viewport->Pos;
9441
9442 // By default, Windows are uniquely identified by their title.
9443 // You can use the "##" and "###" markers to manipulate the display/ID.
9444
9445 // Using "##" to display same title but have unique identifier.
9446 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
9447 ImGui::Begin("Same title as another window##1");
9448 IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
9449 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
9450 ImGui::End();
9451
9452 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
9453 ImGui::Begin("Same title as another window##2");
9454 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
9455 ImGui::End();
9456
9457 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
9458 char buf[128];
9459 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
9460 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
9461 ImGui::Begin(buf);
9462 ImGui::Text("This window has a changing title.");
9463 ImGui::End();
9464}
9465
9466//-----------------------------------------------------------------------------
9467// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
9468//-----------------------------------------------------------------------------
9469
9470// Add a |_| looking shape
9471static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
9472{
9473 const ImVec2 pos_norms[] = { { 0.0f, 0.0f }, { 0.3f, 0.0f }, { 0.3f, 0.7f }, { 0.7f, 0.7f }, { 0.7f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 0.0f, 1.0f } };
9474 for (const ImVec2& p : pos_norms)
9475 draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
9476}
9477
9478// Demonstrate using the low-level ImDrawList to draw custom shapes.
9479static void ShowExampleAppCustomRendering(bool* p_open)
9480{
9481 if (!ImGui::Begin("Example: Custom rendering", p_open))
9482 {
9483 ImGui::End();
9484 return;
9485 }
9486 IMGUI_DEMO_MARKER("Examples/Custom Rendering");
9487
9488 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
9489 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
9490 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
9491 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
9492
9493 if (ImGui::BeginTabBar("##TabBar"))
9494 {
9495 if (ImGui::BeginTabItem("Primitives"))
9496 {
9497 ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
9498 ImDrawList* draw_list = ImGui::GetWindowDrawList();
9499
9500 // Draw gradients
9501 // (note that those are currently exacerbating our sRGB/Linear issues)
9502 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
9503 ImGui::Text("Gradients");
9504 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
9505 {
9506 ImVec2 p0 = ImGui::GetCursorScreenPos();
9507 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9508 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
9509 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
9510 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9511 ImGui::InvisibleButton("##gradient1", gradient_size);
9512 }
9513 {
9514 ImVec2 p0 = ImGui::GetCursorScreenPos();
9515 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
9516 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
9517 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
9518 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
9519 ImGui::InvisibleButton("##gradient2", gradient_size);
9520 }
9521
9522 // Draw a bunch of primitives
9523 ImGui::Text("All primitives");
9524 static float sz = 36.0f;
9525 static float thickness = 3.0f;
9526 static int ngon_sides = 6;
9527 static bool circle_segments_override = false;
9528 static int circle_segments_override_v = 12;
9529 static bool curve_segments_override = false;
9530 static int curve_segments_override_v = 8;
9531 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
9532 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
9533 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
9534 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
9535 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
9536 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9537 circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
9538 ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
9539 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
9540 curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
9541 ImGui::ColorEdit4("Color", &colf.x);
9542
9543 const ImVec2 p = ImGui::GetCursorScreenPos();
9544 const ImU32 col = ImColor(colf);
9545 const float spacing = 10.0f;
9546 const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
9547 const float rounding = sz / 5.0f;
9548 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
9549 const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
9550 const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
9551 const ImVec2 cp4[4] = { ImVec2(0.0f, 0.0f), ImVec2(sz * 1.3f, sz * 0.3f), ImVec2(sz - sz * 1.3f, sz - sz * 0.3f), ImVec2(sz, sz) };
9552
9553 float x = p.x + 4.0f;
9554 float y = p.y + 4.0f;
9555 for (int n = 0; n < 2; n++)
9556 {
9557 // First line uses a thickness of 1.0f, second line uses the configurable thickness
9558 float th = (n == 0) ? 1.0f : thickness;
9559 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
9560 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
9561 draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse
9562 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
9563 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
9564 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners
9565 draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle
9566 //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle
9567 PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape
9568 //draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th);
9569 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
9570 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
9571 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
9572
9573 // Path
9574 draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
9575 draw_list->PathStroke(col, ImDrawFlags_None, th);
9576 x += sz + spacing;
9577
9578 // Quadratic Bezier Curve (3 control points)
9579 draw_list->AddBezierQuadratic(ImVec2(x + cp3[0].x, y + cp3[0].y), ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), col, th, curve_segments);
9580 x += sz + spacing;
9581
9582 // Cubic Bezier Curve (4 control points)
9583 draw_list->AddBezierCubic(ImVec2(x + cp4[0].x, y + cp4[0].y), ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), col, th, curve_segments);
9584
9585 x = p.x + 4;
9586 y += sz + spacing;
9587 }
9588
9589 // Filled shapes
9590 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon
9591 draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle
9592 draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), ImVec2(sz * 0.5f, sz * 0.3f), col, -0.3f, circle_segments); x += sz + spacing;// Ellipse
9593 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
9594 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners
9595 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners
9596 draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle
9597 //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle
9598 PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape
9599 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness)
9600 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness)
9601 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
9602
9603 // Path
9604 draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f);
9605 draw_list->PathFillConvex(col);
9606 x += sz + spacing;
9607
9608 // Quadratic Bezier Curve (3 control points)
9609 draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y));
9610 draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments);
9611 draw_list->PathFillConvex(col);
9612 x += sz + spacing;
9613
9614 draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255));
9615 x += sz + spacing;
9616
9617 ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
9618 ImGui::PopItemWidth();
9619 ImGui::EndTabItem();
9620 }
9621
9622 if (ImGui::BeginTabItem("Canvas"))
9623 {
9624 static ImVector<ImVec2> points;
9625 static ImVec2 scrolling(0.0f, 0.0f);
9626 static bool opt_enable_grid = true;
9627 static bool opt_enable_context_menu = true;
9628 static bool adding_line = false;
9629
9630 ImGui::Checkbox("Enable grid", &opt_enable_grid);
9631 ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
9632 ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
9633
9634 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
9635 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
9636 // To use a child window instead we could use, e.g:
9637 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
9638 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
9639 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove);
9640 // ImGui::PopStyleColor();
9641 // ImGui::PopStyleVar();
9642 // [...]
9643 // ImGui::EndChild();
9644
9645 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
9646 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
9647 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
9648 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
9649 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
9650 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
9651
9652 // Draw border and background color
9653 ImGuiIO& io = ImGui::GetIO();
9654 ImDrawList* draw_list = ImGui::GetWindowDrawList();
9655 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
9656 draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
9657
9658 // This will catch our interactions
9659 ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
9660 const bool is_hovered = ImGui::IsItemHovered(); // Hovered
9661 const bool is_active = ImGui::IsItemActive(); // Held
9662 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
9663 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
9664
9665 // Add first and second point
9666 if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
9667 {
9668 points.push_back(mouse_pos_in_canvas);
9669 points.push_back(mouse_pos_in_canvas);
9670 adding_line = true;
9671 }
9672 if (adding_line)
9673 {
9674 points.back() = mouse_pos_in_canvas;
9675 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
9676 adding_line = false;
9677 }
9678
9679 // Pan (we use a zero mouse threshold when there's no context menu)
9680 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
9681 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
9682 if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
9683 {
9684 scrolling.x += io.MouseDelta.x;
9685 scrolling.y += io.MouseDelta.y;
9686 }
9687
9688 // Context menu (under default mouse threshold)
9689 ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
9690 if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
9691 ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
9692 if (ImGui::BeginPopup("context"))
9693 {
9694 if (adding_line)
9695 points.resize(points.size() - 2);
9696 adding_line = false;
9697 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
9698 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
9699 ImGui::EndPopup();
9700 }
9701
9702 // Draw grid + all lines in the canvas
9703 draw_list->PushClipRect(canvas_p0, canvas_p1, true);
9704 if (opt_enable_grid)
9705 {
9706 const float GRID_STEP = 64.0f;
9707 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
9708 draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
9709 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
9710 draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
9711 }
9712 for (int n = 0; n < points.Size; n += 2)
9713 draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
9714 draw_list->PopClipRect();
9715
9716 ImGui::EndTabItem();
9717 }
9718
9719 if (ImGui::BeginTabItem("BG/FG draw lists"))
9720 {
9721 static bool draw_bg = true;
9722 static bool draw_fg = true;
9723 ImGui::Checkbox("Draw in Background draw list", &draw_bg);
9724 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
9725 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
9726 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
9727 ImVec2 window_pos = ImGui::GetWindowPos();
9728 ImVec2 window_size = ImGui::GetWindowSize();
9729 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
9730 if (draw_bg)
9731 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
9732 if (draw_fg)
9733 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
9734 ImGui::EndTabItem();
9735 }
9736
9737 // Demonstrate out-of-order rendering via channels splitting
9738 // We use functions in ImDrawList as each draw list contains a convenience splitter,
9739 // but you can also instantiate your own ImDrawListSplitter if you need to nest them.
9740 if (ImGui::BeginTabItem("Draw Channels"))
9741 {
9742 ImDrawList* draw_list = ImGui::GetWindowDrawList();
9743 {
9744 ImGui::Text("Blue shape is drawn first: appears in back");
9745 ImGui::Text("Red shape is drawn after: appears in front");
9746 ImVec2 p0 = ImGui::GetCursorScreenPos();
9747 draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9748 draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9749 ImGui::Dummy(ImVec2(75, 75));
9750 }
9751 ImGui::Separator();
9752 {
9753 ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
9754 ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
9755 ImVec2 p1 = ImGui::GetCursorScreenPos();
9756
9757 // Create 2 channels and draw a Blue shape THEN a Red shape.
9758 // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
9759 draw_list->ChannelsSplit(2);
9760 draw_list->ChannelsSetCurrent(1);
9761 draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
9762 draw_list->ChannelsSetCurrent(0);
9763 draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
9764
9765 // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
9766 // This works by copying draw indices only (vertices are not copied).
9767 draw_list->ChannelsMerge();
9768 ImGui::Dummy(ImVec2(75, 75));
9769 ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
9770 }
9771 ImGui::EndTabItem();
9772 }
9773
9774 ImGui::EndTabBar();
9775 }
9776
9777 ImGui::End();
9778}
9779
9780//-----------------------------------------------------------------------------
9781// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
9782//-----------------------------------------------------------------------------
9783
9784// Demonstrate using DockSpace() to create an explicit docking node within an existing window.
9785// Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking!
9786// - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
9787// - Drag from window menu button (upper-left button) to undock an entire node (all windows).
9788// - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking.
9789// About dockspaces:
9790// - Use DockSpace() to create an explicit dock node _within_ an existing window.
9791// - Use DockSpaceOverViewport() to create an explicit dock node covering the screen or a specific viewport.
9792// This is often used with ImGuiDockNodeFlags_PassthruCentralNode.
9793// - Important: Dockspaces need to be submitted _before_ any window they can host. Submit it early in your frame! (*)
9794// - Important: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
9795// e.g. if you have multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
9796// (*) because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node,
9797// because that window is submitted as part of the part of the NewFrame() call. An easy workaround is that you can create
9798// your own implicit "Debug##2" window after calling DockSpace() and leave it in the window stack for anyone to use.
9799void ShowExampleAppDockSpace(bool* p_open)
9800{
9801 // READ THIS !!!
9802 // TL;DR; this demo is more complicated than what most users you would normally use.
9803 // If we remove all options we are showcasing, this demo would become:
9804 // void ShowExampleAppDockSpace()
9805 // {
9806 // ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
9807 // }
9808 // In most cases you should be able to just call DockSpaceOverViewport() and ignore all the code below!
9809 // In this specific demo, we are not using DockSpaceOverViewport() because:
9810 // - (1) we allow the host window to be floating/moveable instead of filling the viewport (when opt_fullscreen == false)
9811 // - (2) we allow the host window to have padding (when opt_padding == true)
9812 // - (3) we expose many flags and need a way to have them visible.
9813 // - (4) we have a local menu bar in the host window (vs. you could use BeginMainMenuBar() + DockSpaceOverViewport()
9814 // in your code, but we don't here because we allow the window to be floating)
9815
9816 static bool opt_fullscreen = true;
9817 static bool opt_padding = false;
9818 static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
9819
9820 // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
9821 // because it would be confusing to have two docking targets within each others.
9822 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
9823 if (opt_fullscreen)
9824 {
9825 const ImGuiViewport* viewport = ImGui::GetMainViewport();
9826 ImGui::SetNextWindowPos(viewport->WorkPos);
9827 ImGui::SetNextWindowSize(viewport->WorkSize);
9828 ImGui::SetNextWindowViewport(viewport->ID);
9829 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
9830 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
9831 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
9832 window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
9833 }
9834 else
9835 {
9836 dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
9837 }
9838
9839 // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
9840 // and handle the pass-thru hole, so we ask Begin() to not render a background.
9841 if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
9842 window_flags |= ImGuiWindowFlags_NoBackground;
9843
9844 // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
9845 // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
9846 // all active windows docked into it will lose their parent and become undocked.
9847 // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
9848 // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
9849 if (!opt_padding)
9850 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
9851 ImGui::Begin("DockSpace Demo", p_open, window_flags);
9852 if (!opt_padding)
9853 ImGui::PopStyleVar();
9854
9855 if (opt_fullscreen)
9856 ImGui::PopStyleVar(2);
9857
9858 // Submit the DockSpace
9859 ImGuiIO& io = ImGui::GetIO();
9860 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
9861 {
9862 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
9863 ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
9864 }
9865 else
9866 {
9867 ShowDockingDisabledMessage();
9868 }
9869
9870 if (ImGui::BeginMenuBar())
9871 {
9872 if (ImGui::BeginMenu("Options"))
9873 {
9874 // Disabling fullscreen would allow the window to be moved to the front of other windows,
9875 // which we can't undo at the moment without finer window depth/z control.
9876 ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
9877 ImGui::MenuItem("Padding", NULL, &opt_padding);
9878 ImGui::Separator();
9879
9880 if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode; }
9881 if (ImGui::MenuItem("Flag: NoDockingSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit; }
9882 if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking; }
9883 if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
9884 if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
9885 if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
9886 ImGui::Separator();
9887
9888 if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
9889 *p_open = false;
9890 ImGui::EndMenu();
9891 }
9892 HelpMarker(
9893 "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
9894 "- Drag from window title bar or their tab to dock/undock." "\n"
9895 "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
9896 "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
9897 "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)" "\n"
9898 "This demo app has nothing to do with enabling docking!" "\n\n"
9899 "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window." "\n\n"
9900 "Read comments in ShowExampleAppDockSpace() for more details.");
9901
9902 ImGui::EndMenuBar();
9903 }
9904
9905 ImGui::End();
9906}
9907
9908//-----------------------------------------------------------------------------
9909// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
9910//-----------------------------------------------------------------------------
9911
9912// Simplified structure to mimic a Document model
9914{
9915 char Name[32]; // Document title
9916 int UID; // Unique ID (necessary as we can change title)
9917 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
9918 bool OpenPrev; // Copy of Open from last update.
9919 bool Dirty; // Set when the document has been modified
9920 ImVec4 Color; // An arbitrary variable associated to the document
9921
9922 MyDocument(int uid, const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
9923 {
9924 UID = uid;
9925 snprintf(Name, sizeof(Name), "%s", name);
9926 Open = OpenPrev = open;
9927 Dirty = false;
9928 Color = color;
9929 }
9930 void DoOpen() { Open = true; }
9931 void DoForceClose() { Open = false; Dirty = false; }
9932 void DoSave() { Dirty = false; }
9933};
9934
9936{
9937 ImVector<MyDocument> Documents;
9938 ImVector<MyDocument*> CloseQueue;
9940 bool RenamingStarted = false;
9941
9943 {
9944 Documents.push_back(MyDocument(0, "Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
9945 Documents.push_back(MyDocument(1, "Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
9946 Documents.push_back(MyDocument(2, "Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
9947 Documents.push_back(MyDocument(3, "Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
9948 Documents.push_back(MyDocument(4, "A Rather Long Title", false, ImVec4(0.4f, 0.8f, 0.8f, 1.0f)));
9949 Documents.push_back(MyDocument(5, "Some Document", false, ImVec4(0.8f, 0.8f, 1.0f, 1.0f)));
9950 }
9951
9952 // As we allow to change document name, we append a never-changing document ID so tabs are stable
9953 void GetTabName(MyDocument* doc, char* out_buf, size_t out_buf_size)
9954 {
9955 snprintf(out_buf, out_buf_size, "%s###doc%d", doc->Name, doc->UID);
9956 }
9957
9958 // Display placeholder contents for the Document
9960 {
9961 ImGui::PushID(doc);
9962 ImGui::Text("Document \"%s\"", doc->Name);
9963 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
9964 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
9965 ImGui::PopStyleColor();
9966
9967 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip);
9968 if (ImGui::Button("Rename.."))
9969 {
9970 RenamingDoc = doc;
9971 RenamingStarted = true;
9972 }
9973 ImGui::SameLine();
9974
9975 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_M, ImGuiInputFlags_Tooltip);
9976 if (ImGui::Button("Modify"))
9977 doc->Dirty = true;
9978
9979 ImGui::SameLine();
9980 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
9981 if (ImGui::Button("Save"))
9982 doc->DoSave();
9983
9984 ImGui::SameLine();
9985 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_W, ImGuiInputFlags_Tooltip);
9986 if (ImGui::Button("Close"))
9987 CloseQueue.push_back(doc);
9988 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
9989 ImGui::PopID();
9990 }
9991
9992 // Display context menu for the Document
9994 {
9995 if (!ImGui::BeginPopupContextItem())
9996 return;
9997
9998 char buf[256];
9999 sprintf(buf, "Save %s", doc->Name);
10000 if (ImGui::MenuItem(buf, "Ctrl+S", false, doc->Open))
10001 doc->DoSave();
10002 if (ImGui::MenuItem("Rename...", "Ctrl+R", false, doc->Open))
10003 RenamingDoc = doc;
10004 if (ImGui::MenuItem("Close", "Ctrl+W", false, doc->Open))
10005 CloseQueue.push_back(doc);
10006 ImGui::EndPopup();
10007 }
10008
10009 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
10010 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
10011 // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
10012 // the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has
10013 // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
10014 // give the impression of a flicker for one frame.
10015 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
10016 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
10018 {
10019 for (MyDocument& doc : Documents)
10020 {
10021 if (!doc.Open && doc.OpenPrev)
10022 ImGui::SetTabItemClosed(doc.Name);
10023 doc.OpenPrev = doc.Open;
10024 }
10025 }
10026};
10027
10028void ShowExampleAppDocuments(bool* p_open)
10029{
10030 static ExampleAppDocuments app;
10031
10032 // Options
10033 enum Target
10034 {
10035 Target_None,
10036 Target_Tab, // Create documents as local tab into a local tab bar
10037 Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace
10038 };
10039 static Target opt_target = Target_Tab;
10040 static bool opt_reorderable = true;
10041 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
10042
10043 // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
10044 // that we emit gets docked into the same spot as the parent window ("Example: Documents").
10045 // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
10046 // not visible, which in turn would stop submitting the "Eggplant" window.
10047 // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
10048 // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
10049
10050 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
10051 if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
10052 {
10053 ImGui::End();
10054 return;
10055 }
10056
10057 // Menu
10058 if (ImGui::BeginMenuBar())
10059 {
10060 if (ImGui::BeginMenu("File"))
10061 {
10062 int open_count = 0;
10063 for (MyDocument& doc : app.Documents)
10064 open_count += doc.Open ? 1 : 0;
10065
10066 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
10067 {
10068 for (MyDocument& doc : app.Documents)
10069 if (!doc.Open && ImGui::MenuItem(doc.Name))
10070 doc.DoOpen();
10071 ImGui::EndMenu();
10072 }
10073 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
10074 for (MyDocument& doc : app.Documents)
10075 app.CloseQueue.push_back(&doc);
10076 if (ImGui::MenuItem("Exit") && p_open)
10077 *p_open = false;
10078 ImGui::EndMenu();
10079 }
10080 ImGui::EndMenuBar();
10081 }
10082
10083 // [Debug] List documents with one checkbox for each
10084 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10085 {
10086 MyDocument& doc = app.Documents[doc_n];
10087 if (doc_n > 0)
10088 ImGui::SameLine();
10089 ImGui::PushID(&doc);
10090 if (ImGui::Checkbox(doc.Name, &doc.Open))
10091 if (!doc.Open)
10092 doc.DoForceClose();
10093 ImGui::PopID();
10094 }
10095 ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
10096 ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
10097 ImGui::PopItemWidth();
10098 bool redock_all = false;
10099 if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
10100 if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
10101
10102 ImGui::Separator();
10103
10104 // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
10105 // They have multiple effects:
10106 // - Display a dot next to the title.
10107 // - Tab is selected when clicking the X close button.
10108 // - Closure is not assumed (will wait for user to stop submitting the tab).
10109 // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
10110 // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
10111 // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
10112 // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
10113
10114 // Tabs
10115 if (opt_target == Target_Tab)
10116 {
10117 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
10118 tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
10119 if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
10120 {
10121 if (opt_reorderable)
10123
10124 // [DEBUG] Stress tests
10125 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
10126 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
10127
10128 // Submit Tabs
10129 for (MyDocument& doc : app.Documents)
10130 {
10131 if (!doc.Open)
10132 continue;
10133
10134 // As we allow to change document name, we append a never-changing document id so tabs are stable
10135 char doc_name_buf[64];
10136 app.GetTabName(&doc, doc_name_buf, sizeof(doc_name_buf));
10137 ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
10138 bool visible = ImGui::BeginTabItem(doc_name_buf, &doc.Open, tab_flags);
10139
10140 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
10141 if (!doc.Open && doc.Dirty)
10142 {
10143 doc.Open = true;
10144 app.CloseQueue.push_back(&doc);
10145 }
10146
10147 app.DisplayDocContextMenu(&doc);
10148 if (visible)
10149 {
10150 app.DisplayDocContents(&doc);
10151 ImGui::EndTabItem();
10152 }
10153 }
10154
10155 ImGui::EndTabBar();
10156 }
10157 }
10158 else if (opt_target == Target_DockSpaceAndWindow)
10159 {
10160 if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
10161 {
10163
10164 // Create a DockSpace node where any window can be docked
10165 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
10166 ImGui::DockSpace(dockspace_id);
10167
10168 // Create Windows
10169 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
10170 {
10171 MyDocument* doc = &app.Documents[doc_n];
10172 if (!doc->Open)
10173 continue;
10174
10175 ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
10176 ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
10177 bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
10178
10179 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
10180 if (!doc->Open && doc->Dirty)
10181 {
10182 doc->Open = true;
10183 app.CloseQueue.push_back(doc);
10184 }
10185
10186 app.DisplayDocContextMenu(doc);
10187 if (visible)
10188 app.DisplayDocContents(doc);
10189
10190 ImGui::End();
10191 }
10192 }
10193 else
10194 {
10195 ShowDockingDisabledMessage();
10196 }
10197 }
10198
10199 // Early out other contents
10200 if (!window_contents_visible)
10201 {
10202 ImGui::End();
10203 return;
10204 }
10205
10206 // Display renaming UI
10207 if (app.RenamingDoc != NULL)
10208 {
10209 if (app.RenamingStarted)
10210 ImGui::OpenPopup("Rename");
10211 if (ImGui::BeginPopup("Rename"))
10212 {
10213 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 30);
10214 if (ImGui::InputText("###Name", app.RenamingDoc->Name, IM_ARRAYSIZE(app.RenamingDoc->Name), ImGuiInputTextFlags_EnterReturnsTrue))
10215 {
10216 ImGui::CloseCurrentPopup();
10217 app.RenamingDoc = NULL;
10218 }
10219 if (app.RenamingStarted)
10220 ImGui::SetKeyboardFocusHere(-1);
10221 ImGui::EndPopup();
10222 }
10223 else
10224 {
10225 app.RenamingDoc = NULL;
10226 }
10227 app.RenamingStarted = false;
10228 }
10229
10230 // Display closing confirmation UI
10231 if (!app.CloseQueue.empty())
10232 {
10233 int close_queue_unsaved_documents = 0;
10234 for (int n = 0; n < app.CloseQueue.Size; n++)
10235 if (app.CloseQueue[n]->Dirty)
10236 close_queue_unsaved_documents++;
10237
10238 if (close_queue_unsaved_documents == 0)
10239 {
10240 // Close documents when all are unsaved
10241 for (int n = 0; n < app.CloseQueue.Size; n++)
10242 app.CloseQueue[n]->DoForceClose();
10243 app.CloseQueue.clear();
10244 }
10245 else
10246 {
10247 if (!ImGui::IsPopupOpen("Save?"))
10248 ImGui::OpenPopup("Save?");
10249 if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
10250 {
10251 ImGui::Text("Save change to the following items?");
10252 float item_height = ImGui::GetTextLineHeightWithSpacing();
10253 if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
10254 for (MyDocument* doc : app.CloseQueue)
10255 if (doc->Dirty)
10256 ImGui::Text("%s", doc->Name);
10257 ImGui::EndChild();
10258
10259 ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
10260 if (ImGui::Button("Yes", button_size))
10261 {
10262 for (MyDocument* doc : app.CloseQueue)
10263 {
10264 if (doc->Dirty)
10265 doc->DoSave();
10266 doc->DoForceClose();
10267 }
10268 app.CloseQueue.clear();
10269 ImGui::CloseCurrentPopup();
10270 }
10271 ImGui::SameLine();
10272 if (ImGui::Button("No", button_size))
10273 {
10274 for (MyDocument* doc : app.CloseQueue)
10275 doc->DoForceClose();
10276 app.CloseQueue.clear();
10277 ImGui::CloseCurrentPopup();
10278 }
10279 ImGui::SameLine();
10280 if (ImGui::Button("Cancel", button_size))
10281 {
10282 app.CloseQueue.clear();
10283 ImGui::CloseCurrentPopup();
10284 }
10285 ImGui::EndPopup();
10286 }
10287 }
10288 }
10289
10290 ImGui::End();
10291}
10292
10293//-----------------------------------------------------------------------------
10294// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
10295//-----------------------------------------------------------------------------
10296
10297//#include "imgui_internal.h" // NavMoveRequestTryWrapping()
10298
10300{
10301 ImGuiID ID;
10302 int Type;
10303
10304 ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; }
10305
10306 static const ImGuiTableSortSpecs* s_current_sort_specs;
10307
10308 static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count)
10309 {
10310 s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
10311 if (items_count > 1)
10312 qsort(items, (size_t)items_count, sizeof(items[0]), ExampleAsset::CompareWithSortSpecs);
10313 s_current_sort_specs = NULL;
10314 }
10315
10316 // Compare function to be used by qsort()
10317 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
10318 {
10319 const ExampleAsset* a = (const ExampleAsset*)lhs;
10320 const ExampleAsset* b = (const ExampleAsset*)rhs;
10321 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
10322 {
10323 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
10324 int delta = 0;
10325 if (sort_spec->ColumnIndex == 0)
10326 delta = ((int)a->ID - (int)b->ID);
10327 else if (sort_spec->ColumnIndex == 1)
10328 delta = (a->Type - b->Type);
10329 if (delta > 0)
10330 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
10331 if (delta < 0)
10332 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
10333 }
10334 return ((int)a->ID - (int)b->ID);
10335 }
10336};
10337const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;
10338
10340{
10341 // Options
10342 bool ShowTypeOverlay = true;
10343 bool AllowSorting = true;
10345 bool AllowBoxSelect = true;
10346 float IconSize = 32.0f;
10347 int IconSpacing = 10;
10348 int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer.
10349 bool StretchSpacing = true;
10350
10351 // State
10352 ImVector<ExampleAsset> Items; // Our items
10353 ExampleSelectionWithDeletion Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
10354 ImGuiID NextItemId = 0; // Unique identifier when creating new items
10355 bool RequestDelete = false; // Deferred deletion request
10356 bool RequestSort = false; // Deferred sort request
10357 float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better
10358
10359 // Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way.
10361 ImVec2 LayoutItemStep; // == LayoutItemSize + LayoutItemSpacing
10362 float LayoutItemSpacing = 0.0f;
10367
10368 // Functions
10370 {
10371 AddItems(10000);
10372 }
10373 void AddItems(int count)
10374 {
10375 if (Items.Size == 0)
10376 NextItemId = 0;
10377 Items.reserve(Items.Size + count);
10378 for (int n = 0; n < count; n++, NextItemId++)
10379 Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
10380 RequestSort = true;
10381 }
10383 {
10384 Items.clear();
10385 Selection.Clear();
10386 }
10387
10388 // Logic would be written in the main code BeginChild() and outputing to local variables.
10389 // We extracted it into a function so we can call it easily from multiple places.
10390 void UpdateLayoutSizes(float avail_width)
10391 {
10392 // Layout: when not stretching: allow extending into right-most spacing.
10394 if (StretchSpacing == false)
10395 avail_width += floorf(LayoutItemSpacing * 0.5f);
10396
10397 // Layout: calculate number of icon per line and number of lines
10398 LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
10399 LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
10401
10402 // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
10405
10408 LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
10409 }
10410
10411 void Draw(const char* title, bool* p_open)
10412 {
10413 ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
10414 if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
10415 {
10416 ImGui::End();
10417 return;
10418 }
10419
10420 // Menu bar
10421 if (ImGui::BeginMenuBar())
10422 {
10423 if (ImGui::BeginMenu("File"))
10424 {
10425 if (ImGui::MenuItem("Add 10000 items"))
10426 AddItems(10000);
10427 if (ImGui::MenuItem("Clear items"))
10428 ClearItems();
10429 ImGui::Separator();
10430 if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
10431 *p_open = false;
10432 ImGui::EndMenu();
10433 }
10434 if (ImGui::BeginMenu("Edit"))
10435 {
10436 if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10437 RequestDelete = true;
10438 ImGui::EndMenu();
10439 }
10440 if (ImGui::BeginMenu("Options"))
10441 {
10442 ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
10443
10444 ImGui::SeparatorText("Contents");
10445 ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay);
10446 ImGui::Checkbox("Allow Sorting", &AllowSorting);
10447
10448 ImGui::SeparatorText("Selection Behavior");
10449 ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected);
10450 ImGui::Checkbox("Allow box-selection", &AllowBoxSelect);
10451
10452 ImGui::SeparatorText("Layout");
10453 ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f");
10454 ImGui::SameLine(); HelpMarker("Use CTRL+Wheel to zoom");
10455 ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
10456 ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
10457 ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
10458 ImGui::PopItemWidth();
10459 ImGui::EndMenu();
10460 }
10461 ImGui::EndMenuBar();
10462 }
10463
10464 // Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
10465 if (AllowSorting)
10466 {
10467 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
10468 ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
10469 if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight())))
10470 {
10471 ImGui::TableSetupColumn("Index");
10472 ImGui::TableSetupColumn("Type");
10473 ImGui::TableHeadersRow();
10474 if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
10475 if (sort_specs->SpecsDirty || RequestSort)
10476 {
10477 ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
10478 sort_specs->SpecsDirty = RequestSort = false;
10479 }
10480 ImGui::EndTable();
10481 }
10482 ImGui::PopStyleVar();
10483 }
10484
10485 ImGuiIO& io = ImGui::GetIO();
10486 ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing)));
10487 if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove))
10488 {
10489 ImDrawList* draw_list = ImGui::GetWindowDrawList();
10490
10491 const float avail_width = ImGui::GetContentRegionAvail().x;
10492 UpdateLayoutSizes(avail_width);
10493
10494 // Calculate and store start position.
10495 ImVec2 start_pos = ImGui::GetCursorScreenPos();
10496 start_pos = ImVec2(start_pos.x + LayoutOuterPadding, start_pos.y + LayoutOuterPadding);
10497 ImGui::SetCursorScreenPos(start_pos);
10498
10499 // Multi-select
10500 ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid;
10501
10502 // - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items)
10503 if (AllowBoxSelect)
10504 ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d;
10505
10506 // - This feature allows dragging an unselected item without selecting it (rarely used)
10508 ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease;
10509
10510 // - Enable keyboard wrapping on X axis
10511 // (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing:
10512 // ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
10513 // When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system)
10514 ms_flags |= ImGuiMultiSelectFlags_NavWrapX;
10515
10516 ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
10517
10518 // Use custom selection adapter: store ID in selection (recommended)
10519 Selection.UserData = this;
10520 Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
10521 Selection.ApplyRequests(ms_io);
10522
10523 const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
10524 const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
10525 RequestDelete = false;
10526
10527 // Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items)
10528 // Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
10529 // But it is necessary for two reasons:
10530 // - Selectables uses it by default to visually fill the space between two items.
10531 // - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do).
10532 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing));
10533
10534 // Rendering parameters
10535 const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) };
10536 const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220));
10537 const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f);
10538 const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x);
10539
10540 const int column_count = LayoutColumnCount;
10541 ImGuiListClipper clipper;
10542 clipper.Begin(LayoutLineCount, LayoutItemStep.y);
10543 if (item_curr_idx_to_focus != -1)
10544 clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
10545 if (ms_io->RangeSrcItem != -1)
10546 clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
10547 while (clipper.Step())
10548 {
10549 for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
10550 {
10551 const int item_min_idx_for_current_line = line_idx * column_count;
10552 const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size);
10553 for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx)
10554 {
10555 ExampleAsset* item_data = &Items[item_idx];
10556 ImGui::PushID((int)item_data->ID);
10557
10558 // Position item
10559 ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y);
10560 ImGui::SetCursorScreenPos(pos);
10561
10562 ImGui::SetNextItemSelectionUserData(item_idx);
10563 bool item_is_selected = Selection.Contains((ImGuiID)item_data->ID);
10564 bool item_is_visible = ImGui::IsRectVisible(LayoutItemSize);
10565 ImGui::Selectable("", item_is_selected, ImGuiSelectableFlags_None, LayoutItemSize);
10566
10567 // Update our selection state immediately (without waiting for EndMultiSelect() requests)
10568 // because we use this to alter the color of our text/icon.
10569 if (ImGui::IsItemToggledSelection())
10570 item_is_selected = !item_is_selected;
10571
10572 // Focus (for after deletion)
10573 if (item_curr_idx_to_focus == item_idx)
10574 ImGui::SetKeyboardFocusHere(-1);
10575
10576 // Drag and drop
10577 if (ImGui::BeginDragDropSource())
10578 {
10579 // Create payload with full selection OR single unselected item.
10580 // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
10581 if (ImGui::GetDragDropPayload() == NULL)
10582 {
10583 ImVector<ImGuiID> payload_items;
10584 void* it = NULL;
10585 ImGuiID id = 0;
10586 if (!item_is_selected)
10587 payload_items.push_back(item_data->ID);
10588 else
10589 while (Selection.GetNextSelectedItem(&it, &id))
10590 payload_items.push_back(id);
10591 ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
10592 }
10593
10594 // Display payload content in tooltip, by extracting it from the payload data
10595 // (we could read from selection, but it is more correct and reusable to read from payload)
10596 const ImGuiPayload* payload = ImGui::GetDragDropPayload();
10597 const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID);
10598 ImGui::Text("%d assets", payload_count);
10599
10600 ImGui::EndDragDropSource();
10601 }
10602
10603 // Render icon (a real app would likely display an image/thumbnail here)
10604 // Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well.
10605 if (item_is_visible)
10606 {
10607 ImVec2 box_min(pos.x - 1, pos.y - 1);
10608 ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious
10609 draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color
10610 if (ShowTypeOverlay && item_data->Type != 0)
10611 {
10612 ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)];
10613 draw_list->AddRectFilled(ImVec2(box_max.x - 2 - icon_type_overlay_size.x, box_min.y + 2), ImVec2(box_max.x - 2, box_min.y + 2 + icon_type_overlay_size.y), type_col);
10614 }
10615 if (display_label)
10616 {
10617 ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled);
10618 char label[32];
10619 sprintf(label, "%d", item_data->ID);
10620 draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label);
10621 }
10622 }
10623
10624 ImGui::PopID();
10625 }
10626 }
10627 }
10628 clipper.End();
10629 ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
10630
10631 // Context menu
10632 if (ImGui::BeginPopupContextWindow())
10633 {
10634 ImGui::Text("Selection: %d items", Selection.Size);
10635 ImGui::Separator();
10636 if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
10637 RequestDelete = true;
10638 ImGui::EndPopup();
10639 }
10640
10641 ms_io = ImGui::EndMultiSelect();
10642 Selection.ApplyRequests(ms_io);
10643 if (want_delete)
10644 Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
10645
10646 // Zooming with CTRL+Wheel
10647 if (ImGui::IsWindowAppearing())
10648 ZoomWheelAccum = 0.0f;
10649 if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
10650 {
10651 ZoomWheelAccum += io.MouseWheel;
10652 if (fabsf(ZoomWheelAccum) >= 1.0f)
10653 {
10654 // Calculate hovered item index from mouse location
10655 // FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it.
10656 const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x;
10657 const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y;
10658 const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx;
10659 //ImGui::SetTooltip("%f,%f -> item %d", hovered_item_nx, hovered_item_ny, hovered_item_idx); // Move those 4 lines in block above for easy debugging
10660
10661 // Zoom
10662 IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
10663 IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
10665 UpdateLayoutSizes(avail_width);
10666
10667 // Manipulate scroll to that we will land at the same Y location of currently hovered item.
10668 // - Calculate next frame position of item under mouse
10669 // - Set new scroll position to be used in next ImGui::BeginChild() call.
10670 float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y;
10671 hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y;
10672 float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y;
10673 ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y);
10674 }
10675 }
10676 }
10677 ImGui::EndChild();
10678
10679 ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
10680 ImGui::End();
10681 }
10682};
10683
10684void ShowExampleAppAssetsBrowser(bool* p_open)
10685{
10686 IMGUI_DEMO_MARKER("Examples/Assets Browser");
10687 static ExampleAssetsBrowser assets_browser;
10688 assets_browser.Draw("Example: Assets Browser", p_open);
10689}
10690
10691// End of Demo code
10692#else
10693
10694void ImGui::ShowAboutWindow(bool*) {}
10695void ImGui::ShowDemoWindow(bool*) {}
10696void ImGui::ShowUserGuide() {}
10697void ImGui::ShowStyleEditor(ImGuiStyle*) {}
10698bool ImGui::ShowStyleSelector(const char* label) { return false; }
10699void ImGui::ShowFontSelector(const char* label) {}
10700
10701#endif
10702
10703#endif // #ifndef IMGUI_DISABLE
uintptr_t id
imat3 i3(ivec3(1, 2, 3), ivec3(4, 5, 6), ivec3(7, 8, 9))
#define IM_NEWLINE
#define IM_CLAMP(V, MN, MX)
#define IMGUI_CDECL
void * GImGuiDemoMarkerCallbackUserData
#define IM_MAX(A, B)
ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback
#define PRIu64
void(* ImGuiDemoMarkerCallback)(const char *file, int line, const char *section, void *user_data)
#define PRId64
#define IM_MIN(A, B)
#define IMGUI_DEMO_MARKER(section)
IMGUI_API void ShowFontAtlas(ImFontAtlas *atlas)
Definition imgui.cc:20934
auto CalcTextSize(std::string_view str)
Definition ImGuiUtils.hh:39
void TextUnformatted(const std::string &str)
Definition ImGuiUtils.hh:26
constexpr double e
Definition Math.hh:21
constexpr double log(double x)
Definition cstd.hh:208
void ID(const char *str_id, std::invocable<> auto next)
Definition ImGuiCpp.hh:244
void Tooltip(std::invocable<> auto next)
Definition ImGuiCpp.hh:374
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
size_t size(std::string_view utf8)
auto filter(ForwardRange &&range, Predicate pred)
Definition view.hh:459
constexpr auto values(Map &&map)
Definition view.hh:452
void Draw(const char *title, bool *p_open)
int TextEditCallback(ImGuiInputTextCallbackData *data)
ImVector< char * > History
ImVector< const char * > Commands
static int TextEditCallbackStub(ImGuiInputTextCallbackData *data)
static void Strtrim(char *s)
static int Stricmp(const char *s1, const char *s2)
ImGuiTextFilter Filter
void AddLog(const char *fmt,...) IM_FMTARGS(2)
static int Strnicmp(const char *s1, const char *s2, int n)
void ExecCommand(const char *command_line)
static char * Strdup(const char *s)
ImVector< char * > Items
void NotifyOfDocumentsClosedElsewhere()
void DisplayDocContents(MyDocument *doc)
void DisplayDocContextMenu(MyDocument *doc)
MyDocument * RenamingDoc
ImVector< MyDocument > Documents
void GetTabName(MyDocument *doc, char *out_buf, size_t out_buf_size)
ImVector< MyDocument * > CloseQueue
ImGuiTextFilter Filter
void Draw(const char *title, bool *p_open=NULL)
ImGuiTextBuffer Buf
ImVector< int > LineOffsets
void AddLog(const char *fmt,...) IM_FMTARGS(2)
ExampleTreeNode * VisibleNode
void DrawTreeNode(ExampleTreeNode *node)
void Draw(ExampleTreeNode *root_node)
ExampleAsset(ImGuiID id, int type)
static void SortWithSortSpecs(ImGuiTableSortSpecs *sort_specs, ExampleAsset *items, int items_count)
static int IMGUI_CDECL CompareWithSortSpecs(const void *lhs, const void *rhs)
static const ImGuiTableSortSpecs * s_current_sort_specs
void Draw(const char *title, bool *p_open)
void UpdateLayoutSizes(float avail_width)
void AddItems(int count)
ImVector< ExampleAsset > Items
ExampleSelectionWithDeletion Selection
ImVector< ImGuiID > Items[2]
static int IMGUI_CDECL CompareItemsByValue(const void *lhs, const void *rhs)
void SortItems(int n)
void MoveSelected(int src, int dst)
void ApplySelectionRequests(ImGuiMultiSelectIO *ms_io, int side)
void MoveAll(int src, int dst)
ImGuiSelectionBasicStorage Selections[2]
const char * Name
ImGuiDataType DataType
int ApplyDeletionPreLoop(ImGuiMultiSelectIO *ms_io, int items_count)
void ApplyDeletionPostLoop(ImGuiMultiSelectIO *ms_io, ImVector< ITEM_TYPE > &items, int item_curr_idx_to_select)
ExampleTreeNode * Parent
unsigned short IndexInParent
ImVector< ExampleTreeNode * > Childs
ExampleTreeNode * DemoTree
void DoOpen()
void DoSave()
void DoForceClose()
MyDocument(int uid, const char *name, bool open=true, const ImVec4 &color=ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
char Name[32]
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)