1// dear imgui, v1.90.5
2// (demo code)
3
4// Help:
5// - Read FAQ at http://dearimgui.com/faq
6// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7// - Need help integrating Dear ImGui in your codebase?
8// - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started
9// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
10// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
11// Get the latest version at https://github.com/ocornut/imgui
12
13//---------------------------------------------------
14// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT!
15//---------------------------------------------------
16// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase:
17// Think again! It is the most useful reference code that you and other coders will want to refer to and call.
18// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app!
19// Also include Metrics! ItemPicker! DebugLog! and other debug features.
20// Removing this file from your project is hindering access to documentation for everyone in your team,
21// likely leading you to poorer usage of the library.
22// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
23// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
24// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
25// In another situation, whenever you have Dear ImGui available you probably want this to be available for reference.
26// Thank you,
27// -Your beloved friend, imgui_demo.cpp (which you won't delete)
28
29//--------------------------------------------
30// ABOUT THE MEANING OF THE 'static' KEYWORD:
31//--------------------------------------------
32// In this demo code, we frequently use 'static' variables inside functions.
33// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function.
34// Think of "static int n = 0;" as "global int n = 0;" !
35// We do this IN THE DEMO because we want:
36// - to gather code and data in the same place.
37// - to make the demo source code faster to read, faster to change, smaller in size.
38// - it is also a convenient way of storing simple UI related information as long as your function
39// doesn't need to be reentrant or used in multiple threads.
40// This might be a pattern you will want to use in your code, but most of the data you would be working
41// with in a complex codebase is likely going to be stored outside your functions.
42
43//-----------------------------------------
44// ABOUT THE CODING STYLE OF OUR DEMO CODE
45//-----------------------------------------
46// The Demo code in this file is designed to be easy to copy-and-paste into your application!
47// Because of this:
48// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
49// - We try to declare static variables in the local scope, as close as possible to the code using them.
50// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
51// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
52// by imgui.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional
53// and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
54// Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
55
56// Navigating this file:
57// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
58// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
59// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
60
61/*
62
63Index of this file:
64
65// [SECTION] Forward Declarations
66// [SECTION] Helpers
67// [SECTION] Demo Window / ShowDemoWindow()
68// - ShowDemoWindow()
69// - sub section: ShowDemoWindowWidgets()
70// - sub section: ShowDemoWindowLayout()
71// - sub section: ShowDemoWindowPopups()
72// - sub section: ShowDemoWindowTables()
73// - sub section: ShowDemoWindowInputs()
74// [SECTION] About Window / ShowAboutWindow()
75// [SECTION] Style Editor / ShowStyleEditor()
76// [SECTION] User Guide / ShowUserGuide()
77// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
78// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
79// [SECTION] Example App: Debug Log / ShowExampleAppLog()
80// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
81// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
82// [SECTION] Example App: Long Text / ShowExampleAppLongText()
83// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
84// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
85// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
86// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
87// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
88// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
89// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
90// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
91
92*/
93
94#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
95#define _CRT_SECURE_NO_WARNINGS
96#endif
97
98#include "imgui.h"
99#ifndef IMGUI_DISABLE
100
101// System includes
102#include <ctype.h> // toupper
103#include <limits.h> // INT_MIN, INT_MAX
104#include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
105#include <stdio.h> // vsnprintf, sscanf, printf
106#include <stdlib.h> // NULL, malloc, free, atoi
107#include <stdint.h> // intptr_t
108#if !defined(_MSC_VER) || _MSC_VER >= 1800
109#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
110#endif
111
112// Visual Studio warnings
113#ifdef _MSC_VER
114#pragma warning (disable: 4127) // condition expression is constant
115#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
116#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).
117#endif
118
119// Clang/GCC warnings with -Weverything
120#if defined(__clang__)
121#if __has_warning("-Wunknown-warning-option")
122#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!
123#endif
124#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
125#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
126#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)
127#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type
128#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal
129#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.
130#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.
131#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
132#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.
133#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
134#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
135#elif defined(__GNUC__)
136#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
137#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
138#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure)
139#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
140#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
141#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.
142#endif
143
144// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
145#ifdef _WIN32
146#define IM_NEWLINE "\r\n"
147#else
148#define IM_NEWLINE "\n"
149#endif
150
151// Helpers
152#if defined(_MSC_VER) && !defined(snprintf)
153#define snprintf _snprintf
154#endif
155#if defined(_MSC_VER) && !defined(vsnprintf)
156#define vsnprintf _vsnprintf
157#endif
158
159// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
160#if !defined(PRId64) && defined(_MSC_VER)
161#define PRId64 "I64d"
162#define PRIu64 "I64u"
163#elif !defined(PRId64)
164#define PRId64 "lld"
165#define PRIu64 "llu"
166#endif
167
168// Helpers macros
169// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
170// but making an exception here as those are largely simplifying code...
171// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
172#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B))
173#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B))
174#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
175
176// Enforce cdecl calling convention for functions called by the standard library,
177// in case compilation settings changed the default to e.g. __vectorcall
178#ifndef IMGUI_CDECL
179#ifdef _MSC_VER
180#define IMGUI_CDECL __cdecl
181#else
182#define IMGUI_CDECL
183#endif
184#endif
185
186//-----------------------------------------------------------------------------
187// [SECTION] Forward Declarations, Helpers
188//-----------------------------------------------------------------------------
189
190#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
191
192// Forward Declarations
193static void ShowExampleAppMainMenuBar();
194static void ShowExampleAppConsole(bool* p_open);
195static void ShowExampleAppCustomRendering(bool* p_open);
196static void ShowExampleAppDockSpace(bool* p_open);
197static void ShowExampleAppDocuments(bool* p_open);
198static void ShowExampleAppLog(bool* p_open);
199static void ShowExampleAppLayout(bool* p_open);
200static void ShowExampleAppPropertyEditor(bool* p_open);
201static void ShowExampleAppSimpleOverlay(bool* p_open);
202static void ShowExampleAppAutoResize(bool* p_open);
203static void ShowExampleAppConstrainedResize(bool* p_open);
204static void ShowExampleAppFullscreen(bool* p_open);
205static void ShowExampleAppLongText(bool* p_open);
206static void ShowExampleAppWindowTitles(bool* p_open);
207static void ShowExampleMenuFile();
208
209// We split the contents of the big ShowDemoWindow() function into smaller functions
210// (because the link time of very large functions grow non-linearly)
211static void ShowDemoWindowWidgets();
212static void ShowDemoWindowLayout();
213static void ShowDemoWindowPopups();
214static void ShowDemoWindowTables();
215static void ShowDemoWindowColumns();
216static void ShowDemoWindowInputs();
217
218//-----------------------------------------------------------------------------
219// [SECTION] Helpers
220//-----------------------------------------------------------------------------
221
222// Helper to display a little (?) mark which shows a tooltip when hovered.
223// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
224static void HelpMarker(const char* desc)
225{
226 ImGui::TextDisabled(fmt: "(?)");
227 if (ImGui::BeginItemTooltip())
228 {
229 ImGui::PushTextWrapPos(wrap_local_pos_x: ImGui::GetFontSize() * 35.0f);
230 ImGui::TextUnformatted(text: desc);
231 ImGui::PopTextWrapPos();
232 ImGui::EndTooltip();
233 }
234}
235
236static void ShowDockingDisabledMessage()
237{
238 ImGuiIO& io = ImGui::GetIO();
239 ImGui::Text(fmt: "ERROR: Docking is not enabled! See Demo > Configuration.");
240 ImGui::Text(fmt: "Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
241 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: 0.0f);
242 if (ImGui::SmallButton(label: "click here"))
243 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
244}
245
246// Helper to wire demo markers located in code to an interactive browser
247typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
248extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback;
249extern void* GImGuiDemoMarkerCallbackUserData;
250ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL;
251void* GImGuiDemoMarkerCallbackUserData = NULL;
252#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
253
254//-----------------------------------------------------------------------------
255// [SECTION] Demo Window / ShowDemoWindow()
256//-----------------------------------------------------------------------------
257// - ShowDemoWindow()
258// - ShowDemoWindowWidgets()
259// - ShowDemoWindowLayout()
260// - ShowDemoWindowPopups()
261// - ShowDemoWindowTables()
262// - ShowDemoWindowColumns()
263// - ShowDemoWindowInputs()
264//-----------------------------------------------------------------------------
265
266// Demonstrate most Dear ImGui features (this is big function!)
267// You may execute this function to experiment with the UI and understand what it does.
268// You may then search for keywords in the code when you are interested by a specific feature.
269void ImGui::ShowDemoWindow(bool* p_open)
270{
271 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
272 // Most functions would normally just assert/crash if the context is missing.
273 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
274
275 // Examples Apps (accessible from the "Examples" menu)
276 static bool show_app_main_menu_bar = false;
277 static bool show_app_console = false;
278 static bool show_app_custom_rendering = false;
279 static bool show_app_dockspace = false;
280 static bool show_app_documents = false;
281 static bool show_app_log = false;
282 static bool show_app_layout = false;
283 static bool show_app_property_editor = false;
284 static bool show_app_simple_overlay = false;
285 static bool show_app_auto_resize = false;
286 static bool show_app_constrained_resize = false;
287 static bool show_app_fullscreen = false;
288 static bool show_app_long_text = false;
289 static bool show_app_window_titles = false;
290
291 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
292 if (show_app_dockspace) ShowExampleAppDockSpace(p_open: &show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
293 if (show_app_documents) ShowExampleAppDocuments(p_open: &show_app_documents); // Process the Document app next, as it may also use a DockSpace()
294 if (show_app_console) ShowExampleAppConsole(p_open: &show_app_console);
295 if (show_app_custom_rendering) ShowExampleAppCustomRendering(p_open: &show_app_custom_rendering);
296 if (show_app_log) ShowExampleAppLog(p_open: &show_app_log);
297 if (show_app_layout) ShowExampleAppLayout(p_open: &show_app_layout);
298 if (show_app_property_editor) ShowExampleAppPropertyEditor(p_open: &show_app_property_editor);
299 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(p_open: &show_app_simple_overlay);
300 if (show_app_auto_resize) ShowExampleAppAutoResize(p_open: &show_app_auto_resize);
301 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(p_open: &show_app_constrained_resize);
302 if (show_app_fullscreen) ShowExampleAppFullscreen(p_open: &show_app_fullscreen);
303 if (show_app_long_text) ShowExampleAppLongText(p_open: &show_app_long_text);
304 if (show_app_window_titles) ShowExampleAppWindowTitles(p_open: &show_app_window_titles);
305
306 // Dear ImGui Tools (accessible from the "Tools" menu)
307 static bool show_tool_metrics = false;
308 static bool show_tool_debug_log = false;
309 static bool show_tool_id_stack_tool = false;
310 static bool show_tool_style_editor = false;
311 static bool show_tool_about = false;
312
313 if (show_tool_metrics)
314 ImGui::ShowMetricsWindow(p_open: &show_tool_metrics);
315 if (show_tool_debug_log)
316 ImGui::ShowDebugLogWindow(p_open: &show_tool_debug_log);
317 if (show_tool_id_stack_tool)
318 ImGui::ShowIDStackToolWindow(p_open: &show_tool_id_stack_tool);
319 if (show_tool_style_editor)
320 {
321 ImGui::Begin(name: "Dear ImGui Style Editor", p_open: &show_tool_style_editor);
322 ImGui::ShowStyleEditor();
323 ImGui::End();
324 }
325 if (show_tool_about)
326 ImGui::ShowAboutWindow(p_open: &show_tool_about);
327
328 // Demonstrate the various window flags. Typically you would just use the default!
329 static bool no_titlebar = false;
330 static bool no_scrollbar = false;
331 static bool no_menu = false;
332 static bool no_move = false;
333 static bool no_resize = false;
334 static bool no_collapse = false;
335 static bool no_close = false;
336 static bool no_nav = false;
337 static bool no_background = false;
338 static bool no_bring_to_front = false;
339 static bool no_docking = false;
340 static bool unsaved_document = false;
341
342 ImGuiWindowFlags window_flags = 0;
343 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
344 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
345 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
346 if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
347 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
348 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
349 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
350 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
351 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
352 if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
353 if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
354 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
355
356 // We specify a default position/size in case there's no data in the .ini file.
357 // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
358 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
359 ImGui::SetNextWindowPos(pos: ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), cond: ImGuiCond_FirstUseEver);
360 ImGui::SetNextWindowSize(size: ImVec2(550, 680), cond: ImGuiCond_FirstUseEver);
361
362 // Main body of the Demo window starts here.
363 if (!ImGui::Begin(name: "Dear ImGui Demo", p_open, flags: window_flags))
364 {
365 // Early out if the window is collapsed, as an optimization.
366 ImGui::End();
367 return;
368 }
369
370 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
371 // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
372 //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f);
373 // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
374 ImGui::PushItemWidth(item_width: ImGui::GetFontSize() * -12);
375
376 // Menu Bar
377 if (ImGui::BeginMenuBar())
378 {
379 if (ImGui::BeginMenu(label: "Menu"))
380 {
381 IMGUI_DEMO_MARKER("Menu/File");
382 ShowExampleMenuFile();
383 ImGui::EndMenu();
384 }
385 if (ImGui::BeginMenu(label: "Examples"))
386 {
387 IMGUI_DEMO_MARKER("Menu/Examples");
388 ImGui::MenuItem(label: "Main menu bar", NULL, p_selected: &show_app_main_menu_bar);
389
390 ImGui::SeparatorText(label: "Mini apps");
391 ImGui::MenuItem(label: "Console", NULL, p_selected: &show_app_console);
392 ImGui::MenuItem(label: "Custom rendering", NULL, p_selected: &show_app_custom_rendering);
393 ImGui::MenuItem(label: "Dockspace", NULL, p_selected: &show_app_dockspace);
394 ImGui::MenuItem(label: "Documents", NULL, p_selected: &show_app_documents);
395 ImGui::MenuItem(label: "Log", NULL, p_selected: &show_app_log);
396 ImGui::MenuItem(label: "Property editor", NULL, p_selected: &show_app_property_editor);
397 ImGui::MenuItem(label: "Simple layout", NULL, p_selected: &show_app_layout);
398 ImGui::MenuItem(label: "Simple overlay", NULL, p_selected: &show_app_simple_overlay);
399
400 ImGui::SeparatorText(label: "Concepts");
401 ImGui::MenuItem(label: "Auto-resizing window", NULL, p_selected: &show_app_auto_resize);
402 ImGui::MenuItem(label: "Constrained-resizing window", NULL, p_selected: &show_app_constrained_resize);
403 ImGui::MenuItem(label: "Fullscreen window", NULL, p_selected: &show_app_fullscreen);
404 ImGui::MenuItem(label: "Long text display", NULL, p_selected: &show_app_long_text);
405 ImGui::MenuItem(label: "Manipulating window titles", NULL, p_selected: &show_app_window_titles);
406
407 ImGui::EndMenu();
408 }
409 //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
410 if (ImGui::BeginMenu(label: "Tools"))
411 {
412 IMGUI_DEMO_MARKER("Menu/Tools");
413#ifndef IMGUI_DISABLE_DEBUG_TOOLS
414 const bool has_debug_tools = true;
415#else
416 const bool has_debug_tools = false;
417#endif
418 ImGui::MenuItem(label: "Metrics/Debugger", NULL, p_selected: &show_tool_metrics, enabled: has_debug_tools);
419 ImGui::MenuItem(label: "Debug Log", NULL, p_selected: &show_tool_debug_log, enabled: has_debug_tools);
420 ImGui::MenuItem(label: "ID Stack Tool", NULL, p_selected: &show_tool_id_stack_tool, enabled: has_debug_tools);
421 ImGui::MenuItem(label: "Style Editor", NULL, p_selected: &show_tool_style_editor);
422 bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent;
423 if (ImGui::MenuItem(label: "Item Picker", NULL, selected: false, enabled: has_debug_tools && is_debugger_present))
424 ImGui::DebugStartItemPicker();
425 if (!is_debugger_present)
426 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.");
427 ImGui::Separator();
428 ImGui::MenuItem(label: "About Dear ImGui", NULL, p_selected: &show_tool_about);
429 ImGui::EndMenu();
430 }
431 ImGui::EndMenuBar();
432 }
433
434 ImGui::Text(fmt: "dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
435 ImGui::Spacing();
436
437 IMGUI_DEMO_MARKER("Help");
438 if (ImGui::CollapsingHeader(label: "Help"))
439 {
440 ImGui::SeparatorText(label: "ABOUT THIS DEMO:");
441 ImGui::BulletText(fmt: "Sections below are demonstrating many aspects of the library.");
442 ImGui::BulletText(fmt: "The \"Examples\" menu above leads to more demo contents.");
443 ImGui::BulletText(fmt: "The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
444 "and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
445
446 ImGui::SeparatorText(label: "PROGRAMMER GUIDE:");
447 ImGui::BulletText(fmt: "See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
448 ImGui::BulletText(fmt: "See comments in imgui.cpp.");
449 ImGui::BulletText(fmt: "See example applications in the examples/ folder.");
450 ImGui::BulletText(fmt: "Read the FAQ at https://www.dearimgui.com/faq/");
451 ImGui::BulletText(fmt: "Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
452 ImGui::BulletText(fmt: "Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
453
454 ImGui::SeparatorText(label: "USER GUIDE:");
455 ImGui::ShowUserGuide();
456 }
457
458 IMGUI_DEMO_MARKER("Configuration");
459 if (ImGui::CollapsingHeader(label: "Configuration"))
460 {
461 ImGuiIO& io = ImGui::GetIO();
462
463 if (ImGui::TreeNode(label: "Configuration##2"))
464 {
465 ImGui::SeparatorText(label: "General");
466 ImGui::CheckboxFlags(label: "io.ConfigFlags: NavEnableKeyboard", flags: &io.ConfigFlags, flags_value: ImGuiConfigFlags_NavEnableKeyboard);
467 ImGui::SameLine(); HelpMarker(desc: "Enable keyboard controls.");
468 ImGui::CheckboxFlags(label: "io.ConfigFlags: NavEnableGamepad", flags: &io.ConfigFlags, flags_value: ImGuiConfigFlags_NavEnableGamepad);
469 ImGui::SameLine(); HelpMarker(desc: "Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
470 ImGui::CheckboxFlags(label: "io.ConfigFlags: NavEnableSetMousePos", flags: &io.ConfigFlags, flags_value: ImGuiConfigFlags_NavEnableSetMousePos);
471 ImGui::SameLine(); HelpMarker(desc: "Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
472 ImGui::CheckboxFlags(label: "io.ConfigFlags: NoMouse", flags: &io.ConfigFlags, flags_value: ImGuiConfigFlags_NoMouse);
473 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
474 {
475 // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
476 if (fmodf(x: (float)ImGui::GetTime(), y: 0.40f) < 0.20f)
477 {
478 ImGui::SameLine();
479 ImGui::Text(fmt: "<<PRESS SPACE TO DISABLE>>");
480 }
481 if (ImGui::IsKeyPressed(key: ImGuiKey_Space))
482 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
483 }
484 ImGui::CheckboxFlags(label: "io.ConfigFlags: NoMouseCursorChange", flags: &io.ConfigFlags, flags_value: ImGuiConfigFlags_NoMouseCursorChange);
485 ImGui::SameLine(); HelpMarker(desc: "Instruct backend to not alter mouse cursor shape and visibility.");
486
487 ImGui::Checkbox(label: "io.ConfigInputTrickleEventQueue", v: &io.ConfigInputTrickleEventQueue);
488 ImGui::SameLine(); HelpMarker(desc: "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.");
489 ImGui::Checkbox(label: "io.MouseDrawCursor", v: &io.MouseDrawCursor);
490 ImGui::SameLine(); HelpMarker(desc: "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).");
491
492 ImGui::SeparatorText(label: "Docking");
493 ImGui::CheckboxFlags(label: "io.ConfigFlags: DockingEnable", flags: &io.ConfigFlags, flags_value: ImGuiConfigFlags_DockingEnable);
494 ImGui::SameLine();
495 if (io.ConfigDockingWithShift)
496 HelpMarker(desc: "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).");
497 else
498 HelpMarker(desc: "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).");
499 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
500 {
501 ImGui::Indent();
502 ImGui::Checkbox(label: "io.ConfigDockingNoSplit", v: &io.ConfigDockingNoSplit);
503 ImGui::SameLine(); HelpMarker(desc: "Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
504 ImGui::Checkbox(label: "io.ConfigDockingWithShift", v: &io.ConfigDockingWithShift);
505 ImGui::SameLine(); HelpMarker(desc: "Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
506 ImGui::Checkbox(label: "io.ConfigDockingAlwaysTabBar", v: &io.ConfigDockingAlwaysTabBar);
507 ImGui::SameLine(); HelpMarker(desc: "Create a docking node and tab-bar on single floating windows.");
508 ImGui::Checkbox(label: "io.ConfigDockingTransparentPayload", v: &io.ConfigDockingTransparentPayload);
509 ImGui::SameLine(); HelpMarker(desc: "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.");
510 ImGui::Unindent();
511 }
512
513 ImGui::SeparatorText(label: "Multi-viewports");
514 ImGui::CheckboxFlags(label: "io.ConfigFlags: ViewportsEnable", flags: &io.ConfigFlags, flags_value: ImGuiConfigFlags_ViewportsEnable);
515 ImGui::SameLine(); HelpMarker(desc: "[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
516 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
517 {
518 ImGui::Indent();
519 ImGui::Checkbox(label: "io.ConfigViewportsNoAutoMerge", v: &io.ConfigViewportsNoAutoMerge);
520 ImGui::SameLine(); HelpMarker(desc: "Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.");
521 ImGui::Checkbox(label: "io.ConfigViewportsNoTaskBarIcon", v: &io.ConfigViewportsNoTaskBarIcon);
522 ImGui::SameLine(); HelpMarker(desc: "Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
523 ImGui::Checkbox(label: "io.ConfigViewportsNoDecoration", v: &io.ConfigViewportsNoDecoration);
524 ImGui::SameLine(); HelpMarker(desc: "Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
525 ImGui::Checkbox(label: "io.ConfigViewportsNoDefaultParent", v: &io.ConfigViewportsNoDefaultParent);
526 ImGui::SameLine(); HelpMarker(desc: "Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
527 ImGui::Unindent();
528 }
529
530 ImGui::SeparatorText(label: "Widgets");
531 ImGui::Checkbox(label: "io.ConfigInputTextCursorBlink", v: &io.ConfigInputTextCursorBlink);
532 ImGui::SameLine(); HelpMarker(desc: "Enable blinking cursor (optional as some users consider it to be distracting).");
533 ImGui::Checkbox(label: "io.ConfigInputTextEnterKeepActive", v: &io.ConfigInputTextEnterKeepActive);
534 ImGui::SameLine(); HelpMarker(desc: "Pressing Enter will keep item active and select contents (single-line only).");
535 ImGui::Checkbox(label: "io.ConfigDragClickToInputText", v: &io.ConfigDragClickToInputText);
536 ImGui::SameLine(); HelpMarker(desc: "Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
537 ImGui::Checkbox(label: "io.ConfigWindowsResizeFromEdges", v: &io.ConfigWindowsResizeFromEdges);
538 ImGui::SameLine(); HelpMarker(desc: "Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback.");
539 ImGui::Checkbox(label: "io.ConfigWindowsMoveFromTitleBarOnly", v: &io.ConfigWindowsMoveFromTitleBarOnly);
540 ImGui::Checkbox(label: "io.ConfigMacOSXBehaviors", v: &io.ConfigMacOSXBehaviors);
541 ImGui::Text(fmt: "Also see Style->Rendering for rendering options.");
542
543 ImGui::SeparatorText(label: "Debug");
544 ImGui::Checkbox(label: "io.ConfigDebugIsDebuggerPresent", v: &io.ConfigDebugIsDebuggerPresent);
545 ImGui::SameLine(); HelpMarker(desc: "Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.");
546 ImGui::BeginDisabled();
547 ImGui::Checkbox(label: "io.ConfigDebugBeginReturnValueOnce", v: &io.ConfigDebugBeginReturnValueOnce); // .
548 ImGui::EndDisabled();
549 ImGui::SameLine(); HelpMarker(desc: "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.");
550 ImGui::Checkbox(label: "io.ConfigDebugBeginReturnValueLoop", v: &io.ConfigDebugBeginReturnValueLoop);
551 ImGui::SameLine(); HelpMarker(desc: "Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.");
552 ImGui::Checkbox(label: "io.ConfigDebugIgnoreFocusLoss", v: &io.ConfigDebugIgnoreFocusLoss);
553 ImGui::SameLine(); HelpMarker(desc: "Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
554 ImGui::Checkbox(label: "io.ConfigDebugIniSettings", v: &io.ConfigDebugIniSettings);
555 ImGui::SameLine(); HelpMarker(desc: "Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
556
557 ImGui::TreePop();
558 ImGui::Spacing();
559 }
560
561 IMGUI_DEMO_MARKER("Configuration/Backend Flags");
562 if (ImGui::TreeNode(label: "Backend Flags"))
563 {
564 HelpMarker(
565 desc: "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
566 "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
567
568 // Make a local copy to avoid modifying actual backend flags.
569 // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
570 ImGui::BeginDisabled();
571 ImGui::CheckboxFlags(label: "io.BackendFlags: HasGamepad", flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_HasGamepad);
572 ImGui::CheckboxFlags(label: "io.BackendFlags: HasMouseCursors", flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_HasMouseCursors);
573 ImGui::CheckboxFlags(label: "io.BackendFlags: HasSetMousePos", flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_HasSetMousePos);
574 ImGui::CheckboxFlags(label: "io.BackendFlags: PlatformHasViewports", flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_PlatformHasViewports);
575 ImGui::CheckboxFlags(label: "io.BackendFlags: HasMouseHoveredViewport",flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_HasMouseHoveredViewport);
576 ImGui::CheckboxFlags(label: "io.BackendFlags: RendererHasVtxOffset", flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_RendererHasVtxOffset);
577 ImGui::CheckboxFlags(label: "io.BackendFlags: RendererHasViewports", flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_RendererHasViewports);
578 ImGui::EndDisabled();
579 ImGui::TreePop();
580 ImGui::Spacing();
581 }
582
583 IMGUI_DEMO_MARKER("Configuration/Style");
584 if (ImGui::TreeNode(label: "Style"))
585 {
586 HelpMarker(desc: "The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
587 ImGui::ShowStyleEditor();
588 ImGui::TreePop();
589 ImGui::Spacing();
590 }
591
592 IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
593 if (ImGui::TreeNode(label: "Capture/Logging"))
594 {
595 HelpMarker(
596 desc: "The logging API redirects all text output so you can easily capture the content of "
597 "a window or a block. Tree nodes can be automatically expanded.\n"
598 "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
599 ImGui::LogButtons();
600
601 HelpMarker(desc: "You can also call ImGui::LogText() to output directly to the log without a visual output.");
602 if (ImGui::Button(label: "Copy \"Hello, world!\" to clipboard"))
603 {
604 ImGui::LogToClipboard();
605 ImGui::LogText(fmt: "Hello, world!");
606 ImGui::LogFinish();
607 }
608 ImGui::TreePop();
609 }
610 }
611
612 IMGUI_DEMO_MARKER("Window options");
613 if (ImGui::CollapsingHeader(label: "Window options"))
614 {
615 if (ImGui::BeginTable(str_id: "split", column: 3))
616 {
617 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No titlebar", v: &no_titlebar);
618 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No scrollbar", v: &no_scrollbar);
619 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No menu", v: &no_menu);
620 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No move", v: &no_move);
621 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No resize", v: &no_resize);
622 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No collapse", v: &no_collapse);
623 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No close", v: &no_close);
624 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No nav", v: &no_nav);
625 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No background", v: &no_background);
626 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No bring to front", v: &no_bring_to_front);
627 ImGui::TableNextColumn(); ImGui::Checkbox(label: "No docking", v: &no_docking);
628 ImGui::TableNextColumn(); ImGui::Checkbox(label: "Unsaved document", v: &unsaved_document);
629 ImGui::EndTable();
630 }
631 }
632
633 // All demo contents
634 ShowDemoWindowWidgets();
635 ShowDemoWindowLayout();
636 ShowDemoWindowPopups();
637 ShowDemoWindowTables();
638 ShowDemoWindowInputs();
639
640 // End of ShowDemoWindow()
641 ImGui::PopItemWidth();
642 ImGui::End();
643}
644
645static void ShowDemoWindowWidgets()
646{
647 IMGUI_DEMO_MARKER("Widgets");
648 if (!ImGui::CollapsingHeader(label: "Widgets"))
649 return;
650
651 static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom
652 if (disable_all)
653 ImGui::BeginDisabled();
654
655 IMGUI_DEMO_MARKER("Widgets/Basic");
656 if (ImGui::TreeNode(label: "Basic"))
657 {
658 ImGui::SeparatorText(label: "General");
659
660 IMGUI_DEMO_MARKER("Widgets/Basic/Button");
661 static int clicked = 0;
662 if (ImGui::Button(label: "Button"))
663 clicked++;
664 if (clicked & 1)
665 {
666 ImGui::SameLine();
667 ImGui::Text(fmt: "Thanks for clicking me!");
668 }
669
670 IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
671 static bool check = true;
672 ImGui::Checkbox(label: "checkbox", v: &check);
673
674 IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
675 static int e = 0;
676 ImGui::RadioButton(label: "radio a", v: &e, v_button: 0); ImGui::SameLine();
677 ImGui::RadioButton(label: "radio b", v: &e, v_button: 1); ImGui::SameLine();
678 ImGui::RadioButton(label: "radio c", v: &e, v_button: 2);
679
680 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
681 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
682 for (int i = 0; i < 7; i++)
683 {
684 if (i > 0)
685 ImGui::SameLine();
686 ImGui::PushID(int_id: i);
687 ImGui::PushStyleColor(idx: ImGuiCol_Button, col: (ImVec4)ImColor::HSV(h: i / 7.0f, s: 0.6f, v: 0.6f));
688 ImGui::PushStyleColor(idx: ImGuiCol_ButtonHovered, col: (ImVec4)ImColor::HSV(h: i / 7.0f, s: 0.7f, v: 0.7f));
689 ImGui::PushStyleColor(idx: ImGuiCol_ButtonActive, col: (ImVec4)ImColor::HSV(h: i / 7.0f, s: 0.8f, v: 0.8f));
690 ImGui::Button(label: "Click");
691 ImGui::PopStyleColor(count: 3);
692 ImGui::PopID();
693 }
694
695 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
696 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
697 // See 'Demo->Layout->Text Baseline Alignment' for details.
698 ImGui::AlignTextToFramePadding();
699 ImGui::Text(fmt: "Hold to repeat:");
700 ImGui::SameLine();
701
702 // Arrow buttons with Repeater
703 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
704 static int counter = 0;
705 float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
706 ImGui::PushButtonRepeat(repeat: true);
707 if (ImGui::ArrowButton(str_id: "##left", dir: ImGuiDir_Left)) { counter--; }
708 ImGui::SameLine(offset_from_start_x: 0.0f, spacing);
709 if (ImGui::ArrowButton(str_id: "##right", dir: ImGuiDir_Right)) { counter++; }
710 ImGui::PopButtonRepeat();
711 ImGui::SameLine();
712 ImGui::Text(fmt: "%d", counter);
713
714 ImGui::Button(label: "Tooltip");
715 ImGui::SetItemTooltip("I am a tooltip");
716
717 ImGui::LabelText(label: "label", fmt: "Value");
718
719 ImGui::SeparatorText(label: "Inputs");
720
721 {
722 // To wire InputText() with std::string or any other custom string type,
723 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
724 IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
725 static char str0[128] = "Hello, world!";
726 ImGui::InputText(label: "input text", buf: str0, IM_ARRAYSIZE(str0));
727 ImGui::SameLine(); HelpMarker(
728 desc: "USER:\n"
729 "Hold SHIFT or use mouse to select text.\n"
730 "CTRL+Left/Right to word jump.\n"
731 "CTRL+A or Double-Click to select all.\n"
732 "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
733 "CTRL+Z,CTRL+Y undo/redo.\n"
734 "ESCAPE to revert.\n\n"
735 "PROGRAMMER:\n"
736 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
737 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
738 "in imgui_demo.cpp).");
739
740 static char str1[128] = "";
741 ImGui::InputTextWithHint(label: "input text (w/ hint)", hint: "enter text here", buf: str1, IM_ARRAYSIZE(str1));
742
743 IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
744 static int i0 = 123;
745 ImGui::InputInt(label: "input int", v: &i0);
746
747 static float f0 = 0.001f;
748 ImGui::InputFloat(label: "input float", v: &f0, step: 0.01f, step_fast: 1.0f, format: "%.3f");
749
750 static double d0 = 999999.00000001;
751 ImGui::InputDouble(label: "input double", v: &d0, step: 0.01f, step_fast: 1.0f, format: "%.8f");
752
753 static float f1 = 1.e10f;
754 ImGui::InputFloat(label: "input scientific", v: &f1, step: 0.0f, step_fast: 0.0f, format: "%e");
755 ImGui::SameLine(); HelpMarker(
756 desc: "You can input value using the scientific notation,\n"
757 " e.g. \"1e+8\" becomes \"100000000\".");
758
759 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
760 ImGui::InputFloat3(label: "input float3", v: vec4a);
761 }
762
763 ImGui::SeparatorText(label: "Drags");
764
765 {
766 IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
767 static int i1 = 50, i2 = 42;
768 ImGui::DragInt(label: "drag int", v: &i1, v_speed: 1);
769 ImGui::SameLine(); HelpMarker(
770 desc: "Click and drag to edit value.\n"
771 "Hold SHIFT/ALT for faster/slower edit.\n"
772 "Double-click or CTRL+click to input value.");
773
774 ImGui::DragInt(label: "drag int 0..100", v: &i2, v_speed: 1, v_min: 0, v_max: 100, format: "%d%%", flags: ImGuiSliderFlags_AlwaysClamp);
775
776 static float f1 = 1.00f, f2 = 0.0067f;
777 ImGui::DragFloat(label: "drag float", v: &f1, v_speed: 0.005f);
778 ImGui::DragFloat(label: "drag small float", v: &f2, v_speed: 0.0001f, v_min: 0.0f, v_max: 0.0f, format: "%.06f ns");
779 }
780
781 ImGui::SeparatorText(label: "Sliders");
782
783 {
784 IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
785 static int i1 = 0;
786 ImGui::SliderInt(label: "slider int", v: &i1, v_min: -1, v_max: 3);
787 ImGui::SameLine(); HelpMarker(desc: "CTRL+click to input value.");
788
789 static float f1 = 0.123f, f2 = 0.0f;
790 ImGui::SliderFloat(label: "slider float", v: &f1, v_min: 0.0f, v_max: 1.0f, format: "ratio = %.3f");
791 ImGui::SliderFloat(label: "slider float (log)", v: &f2, v_min: -10.0f, v_max: 10.0f, format: "%.4f", flags: ImGuiSliderFlags_Logarithmic);
792
793 IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
794 static float angle = 0.0f;
795 ImGui::SliderAngle(label: "slider angle", v_rad: &angle);
796
797 // Using the format string to display a name instead of an integer.
798 // Here we completely omit '%d' from the format string, so it'll only display a name.
799 // This technique can also be used with DragInt().
800 IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
801 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
802 static int elem = Element_Fire;
803 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
804 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
805 ImGui::SliderInt(label: "slider enum", v: &elem, v_min: 0, v_max: Element_COUNT - 1, format: elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here.
806 ImGui::SameLine(); HelpMarker(desc: "Using the format string parameter to display a name instead of the underlying integer.");
807 }
808
809 ImGui::SeparatorText(label: "Selectors/Pickers");
810
811 {
812 IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
813 static float col1[3] = { 1.0f, 0.0f, 0.2f };
814 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
815 ImGui::ColorEdit3(label: "color 1", col: col1);
816 ImGui::SameLine(); HelpMarker(
817 desc: "Click on the color square to open a color picker.\n"
818 "Click and hold to use drag and drop.\n"
819 "Right-click on the color square to show options.\n"
820 "CTRL+click on individual component to input value.\n");
821
822 ImGui::ColorEdit4(label: "color 2", col: col2);
823 }
824
825 {
826 // Using the _simplified_ one-liner Combo() api here
827 // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
828 IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
829 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
830 static int item_current = 0;
831 ImGui::Combo(label: "combo", current_item: &item_current, items, IM_ARRAYSIZE(items));
832 ImGui::SameLine(); HelpMarker(
833 desc: "Using the simplified one-liner Combo API here.\n"
834 "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
835 }
836
837 {
838 // Using the _simplified_ one-liner ListBox() api here
839 // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
840 IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
841 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
842 static int item_current = 1;
843 ImGui::ListBox(label: "listbox", current_item: &item_current, items, IM_ARRAYSIZE(items), height_in_items: 4);
844 ImGui::SameLine(); HelpMarker(
845 desc: "Using the simplified one-liner ListBox API here.\n"
846 "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
847 }
848
849 ImGui::TreePop();
850 }
851
852 IMGUI_DEMO_MARKER("Widgets/Tooltips");
853 if (ImGui::TreeNode(label: "Tooltips"))
854 {
855 // Tooltips are windows following the mouse. They do not take focus away.
856 ImGui::SeparatorText(label: "General");
857
858 // Typical use cases:
859 // - Short-form (text only): SetItemTooltip("Hello");
860 // - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
861
862 // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); }
863 // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
864
865 HelpMarker(
866 desc: "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
867 "We provide a helper SetItemTooltip() function to perform the two with standards flags.");
868
869 ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
870
871 ImGui::Button(label: "Basic", size: sz);
872 ImGui::SetItemTooltip("I am a tooltip");
873
874 ImGui::Button(label: "Fancy", size: sz);
875 if (ImGui::BeginItemTooltip())
876 {
877 ImGui::Text(fmt: "I am a fancy tooltip");
878 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
879 ImGui::PlotLines(label: "Curve", values: arr, IM_ARRAYSIZE(arr));
880 ImGui::Text(fmt: "Sin(time) = %f", sinf(x: (float)ImGui::GetTime()));
881 ImGui::EndTooltip();
882 }
883
884 ImGui::SeparatorText(label: "Always On");
885
886 // Showcase NOT relying on a IsItemHovered() to emit a tooltip.
887 // Here the tooltip is always emitted when 'always_on == true'.
888 static int always_on = 0;
889 ImGui::RadioButton(label: "Off", v: &always_on, v_button: 0);
890 ImGui::SameLine();
891 ImGui::RadioButton(label: "Always On (Simple)", v: &always_on, v_button: 1);
892 ImGui::SameLine();
893 ImGui::RadioButton(label: "Always On (Advanced)", v: &always_on, v_button: 2);
894 if (always_on == 1)
895 ImGui::SetTooltip("I am following you around.");
896 else if (always_on == 2 && ImGui::BeginTooltip())
897 {
898 ImGui::ProgressBar(fraction: sinf(x: (float)ImGui::GetTime()) * 0.5f + 0.5f, size_arg: ImVec2(ImGui::GetFontSize() * 25, 0.0f));
899 ImGui::EndTooltip();
900 }
901
902 ImGui::SeparatorText(label: "Custom");
903
904 HelpMarker(
905 desc: "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize"
906 "tooltip activation details across your application. You may however decide to use custom"
907 "flags for a specific tooltip instance.");
908
909 // The following examples are passed for documentation purpose but may not be useful to most users.
910 // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
911 // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or gamepad/keyboard is being used.
912 // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
913 ImGui::Button(label: "Manual", size: sz);
914 if (ImGui::IsItemHovered(flags: ImGuiHoveredFlags_ForTooltip))
915 ImGui::SetTooltip("I am a manually emitted tooltip.");
916
917 ImGui::Button(label: "DelayNone", size: sz);
918 if (ImGui::IsItemHovered(flags: ImGuiHoveredFlags_DelayNone))
919 ImGui::SetTooltip("I am a tooltip with no delay.");
920
921 ImGui::Button(label: "DelayShort", size: sz);
922 if (ImGui::IsItemHovered(flags: ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
923 ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
924
925 ImGui::Button(label: "DelayLong", size: sz);
926 if (ImGui::IsItemHovered(flags: ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
927 ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
928
929 ImGui::Button(label: "Stationary", size: sz);
930 if (ImGui::IsItemHovered(flags: ImGuiHoveredFlags_Stationary))
931 ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
932
933 // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
934 // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
935 // As a result, Set
936 ImGui::BeginDisabled();
937 ImGui::Button(label: "Disabled item", size: sz);
938 ImGui::EndDisabled();
939 if (ImGui::IsItemHovered(flags: ImGuiHoveredFlags_ForTooltip))
940 ImGui::SetTooltip("I am a a tooltip for a disabled item.");
941
942 ImGui::TreePop();
943 }
944
945 // Testing ImGuiOnceUponAFrame helper.
946 //static ImGuiOnceUponAFrame once;
947 //for (int i = 0; i < 5; i++)
948 // if (once)
949 // ImGui::Text("This will be displayed only once.");
950
951 IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
952 if (ImGui::TreeNode(label: "Tree Nodes"))
953 {
954 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
955 if (ImGui::TreeNode(label: "Basic trees"))
956 {
957 for (int i = 0; i < 5; i++)
958 {
959 // Use SetNextItemOpen() so set the default state of a node to be open. We could
960 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
961 if (i == 0)
962 ImGui::SetNextItemOpen(is_open: true, cond: ImGuiCond_Once);
963
964 if (ImGui::TreeNode(ptr_id: (void*)(intptr_t)i, fmt: "Child %d", i))
965 {
966 ImGui::Text(fmt: "blah blah");
967 ImGui::SameLine();
968 if (ImGui::SmallButton(label: "button")) {}
969 ImGui::TreePop();
970 }
971 }
972 ImGui::TreePop();
973 }
974
975 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
976 if (ImGui::TreeNode(label: "Advanced, with Selectable nodes"))
977 {
978 HelpMarker(
979 desc: "This is a more typical looking tree with selectable nodes.\n"
980 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
981 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
982 static bool align_label_with_current_x_position = false;
983 static bool test_drag_and_drop = false;
984 ImGui::CheckboxFlags(label: "ImGuiTreeNodeFlags_OpenOnArrow", flags: &base_flags, flags_value: ImGuiTreeNodeFlags_OpenOnArrow);
985 ImGui::CheckboxFlags(label: "ImGuiTreeNodeFlags_OpenOnDoubleClick", flags: &base_flags, flags_value: ImGuiTreeNodeFlags_OpenOnDoubleClick);
986 ImGui::CheckboxFlags(label: "ImGuiTreeNodeFlags_SpanAvailWidth", flags: &base_flags, flags_value: ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker(desc: "Extend hit area to all available width instead of allowing more items to be laid out after the node.");
987 ImGui::CheckboxFlags(label: "ImGuiTreeNodeFlags_SpanFullWidth", flags: &base_flags, flags_value: ImGuiTreeNodeFlags_SpanFullWidth);
988 ImGui::CheckboxFlags(label: "ImGuiTreeNodeFlags_SpanAllColumns", flags: &base_flags, flags_value: ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker(desc: "For use in Tables only.");
989 ImGui::Checkbox(label: "Align label with current X position", v: &align_label_with_current_x_position);
990 ImGui::Checkbox(label: "Test tree node as drag source", v: &test_drag_and_drop);
991 ImGui::Text(fmt: "Hello!");
992 if (align_label_with_current_x_position)
993 ImGui::Unindent(indent_w: ImGui::GetTreeNodeToLabelSpacing());
994
995 // 'selection_mask' is dumb representation of what may be user-side selection state.
996 // You may retain selection state inside or outside your objects in whatever format you see fit.
997 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
998 /// of the loop. May be a pointer to your own node type, etc.
999 static int selection_mask = (1 << 2);
1000 int node_clicked = -1;
1001 for (int i = 0; i < 6; i++)
1002 {
1003 // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
1004 // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
1005 ImGuiTreeNodeFlags node_flags = base_flags;
1006 const bool is_selected = (selection_mask & (1 << i)) != 0;
1007 if (is_selected)
1008 node_flags |= ImGuiTreeNodeFlags_Selected;
1009 if (i < 3)
1010 {
1011 // Items 0..2 are Tree Node
1012 bool node_open = ImGui::TreeNodeEx(ptr_id: (void*)(intptr_t)i, flags: node_flags, fmt: "Selectable Node %d", i);
1013 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1014 node_clicked = i;
1015 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1016 {
1017 ImGui::SetDragDropPayload(type: "_TREENODE", NULL, sz: 0);
1018 ImGui::Text(fmt: "This is a drag and drop source");
1019 ImGui::EndDragDropSource();
1020 }
1021 if (node_open)
1022 {
1023 ImGui::BulletText(fmt: "Blah blah\nBlah Blah");
1024 ImGui::TreePop();
1025 }
1026 }
1027 else
1028 {
1029 // Items 3..5 are Tree Leaves
1030 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
1031 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
1032 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
1033 ImGui::TreeNodeEx(ptr_id: (void*)(intptr_t)i, flags: node_flags, fmt: "Selectable Leaf %d", i);
1034 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1035 node_clicked = i;
1036 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1037 {
1038 ImGui::SetDragDropPayload(type: "_TREENODE", NULL, sz: 0);
1039 ImGui::Text(fmt: "This is a drag and drop source");
1040 ImGui::EndDragDropSource();
1041 }
1042 }
1043 }
1044 if (node_clicked != -1)
1045 {
1046 // Update selection state
1047 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
1048 if (ImGui::GetIO().KeyCtrl)
1049 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
1050 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
1051 selection_mask = (1 << node_clicked); // Click to single-select
1052 }
1053 if (align_label_with_current_x_position)
1054 ImGui::Indent(indent_w: ImGui::GetTreeNodeToLabelSpacing());
1055 ImGui::TreePop();
1056 }
1057 ImGui::TreePop();
1058 }
1059
1060 IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1061 if (ImGui::TreeNode(label: "Collapsing Headers"))
1062 {
1063 static bool closable_group = true;
1064 ImGui::Checkbox(label: "Show 2nd header", v: &closable_group);
1065 if (ImGui::CollapsingHeader(label: "Header", flags: ImGuiTreeNodeFlags_None))
1066 {
1067 ImGui::Text(fmt: "IsItemHovered: %d", ImGui::IsItemHovered());
1068 for (int i = 0; i < 5; i++)
1069 ImGui::Text(fmt: "Some content %d", i);
1070 }
1071 if (ImGui::CollapsingHeader(label: "Header with a close button", p_visible: &closable_group))
1072 {
1073 ImGui::Text(fmt: "IsItemHovered: %d", ImGui::IsItemHovered());
1074 for (int i = 0; i < 5; i++)
1075 ImGui::Text(fmt: "More content %d", i);
1076 }
1077 /*
1078 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1079 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1080 */
1081 ImGui::TreePop();
1082 }
1083
1084 IMGUI_DEMO_MARKER("Widgets/Bullets");
1085 if (ImGui::TreeNode(label: "Bullets"))
1086 {
1087 ImGui::BulletText(fmt: "Bullet point 1");
1088 ImGui::BulletText(fmt: "Bullet point 2\nOn multiple lines");
1089 if (ImGui::TreeNode(label: "Tree node"))
1090 {
1091 ImGui::BulletText(fmt: "Another bullet point");
1092 ImGui::TreePop();
1093 }
1094 ImGui::Bullet(); ImGui::Text(fmt: "Bullet point 3 (two calls)");
1095 ImGui::Bullet(); ImGui::SmallButton(label: "Button");
1096 ImGui::TreePop();
1097 }
1098
1099 IMGUI_DEMO_MARKER("Widgets/Text");
1100 if (ImGui::TreeNode(label: "Text"))
1101 {
1102 IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
1103 if (ImGui::TreeNode(label: "Colorful Text"))
1104 {
1105 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
1106 ImGui::TextColored(col: ImVec4(1.0f, 0.0f, 1.0f, 1.0f), fmt: "Pink");
1107 ImGui::TextColored(col: ImVec4(1.0f, 1.0f, 0.0f, 1.0f), fmt: "Yellow");
1108 ImGui::TextDisabled(fmt: "Disabled");
1109 ImGui::SameLine(); HelpMarker(desc: "The TextDisabled color is stored in ImGuiStyle.");
1110 ImGui::TreePop();
1111 }
1112
1113 IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
1114 if (ImGui::TreeNode(label: "Word Wrapping"))
1115 {
1116 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
1117 ImGui::TextWrapped(
1118 fmt: "This text should automatically wrap on the edge of the window. The current implementation "
1119 "for text wrapping follows simple rules suitable for English and possibly other languages.");
1120 ImGui::Spacing();
1121
1122 static float wrap_width = 200.0f;
1123 ImGui::SliderFloat(label: "Wrap width", v: &wrap_width, v_min: -20, v_max: 600, format: "%.0f");
1124
1125 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1126 for (int n = 0; n < 2; n++)
1127 {
1128 ImGui::Text(fmt: "Test paragraph %d:", n);
1129 ImVec2 pos = ImGui::GetCursorScreenPos();
1130 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
1131 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
1132 ImGui::PushTextWrapPos(wrap_local_pos_x: ImGui::GetCursorPos().x + wrap_width);
1133 if (n == 0)
1134 ImGui::Text(fmt: "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);
1135 else
1136 ImGui::Text(fmt: "aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
1137
1138 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
1139 draw_list->AddRect(p_min: ImGui::GetItemRectMin(), p_max: ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
1140 draw_list->AddRectFilled(p_min: marker_min, p_max: marker_max, IM_COL32(255, 0, 255, 255));
1141 ImGui::PopTextWrapPos();
1142 }
1143
1144 ImGui::TreePop();
1145 }
1146
1147 IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
1148 if (ImGui::TreeNode(label: "UTF-8 Text"))
1149 {
1150 // UTF-8 test with Japanese characters
1151 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
1152 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
1153 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
1154 // can save your source files as 'UTF-8 without signature').
1155 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
1156 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
1157 // Don't do this in your application! Please use u8"text in any language" in your application!
1158 // Note that characters values are preserved even by InputText() if the font cannot be displayed,
1159 // so you can safely copy & paste garbled characters into another application.
1160 ImGui::TextWrapped(
1161 fmt: "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
1162 "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
1163 "Read docs/FONTS.md for details.");
1164 ImGui::Text(fmt: "Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
1165 ImGui::Text(fmt: "Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
1166 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
1167 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
1168 ImGui::InputText(label: "UTF-8 input", buf, IM_ARRAYSIZE(buf));
1169 ImGui::TreePop();
1170 }
1171 ImGui::TreePop();
1172 }
1173
1174 IMGUI_DEMO_MARKER("Widgets/Images");
1175 if (ImGui::TreeNode(label: "Images"))
1176 {
1177 ImGuiIO& io = ImGui::GetIO();
1178 ImGui::TextWrapped(
1179 fmt: "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1180 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1181 "Hover the texture for a zoomed view!");
1182
1183 // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1184 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
1185 // will be passed to the rendering backend via the ImDrawCmd structure.
1186 // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1187 // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
1188 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
1189 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1190 // More:
1191 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1192 // to ImGui::Image(), and gather width/height through your own functions, etc.
1193 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1194 // it will help you debug issues if you are confused about it.
1195 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1196 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1197 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1198 ImTextureID my_tex_id = io.Fonts->TexID;
1199 float my_tex_w = (float)io.Fonts->TexWidth;
1200 float my_tex_h = (float)io.Fonts->TexHeight;
1201 {
1202 static bool use_text_color_for_tint = false;
1203 ImGui::Checkbox(label: "Use Text Color for Tint", v: &use_text_color_for_tint);
1204 ImGui::Text(fmt: "%.0fx%.0f", my_tex_w, my_tex_h);
1205 ImVec2 pos = ImGui::GetCursorScreenPos();
1206 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1207 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1208 ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(idx: ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1209 ImVec4 border_col = ImGui::GetStyleColorVec4(idx: ImGuiCol_Border);
1210 ImGui::Image(user_texture_id: my_tex_id, image_size: ImVec2(my_tex_w, my_tex_h), uv0: uv_min, uv1: uv_max, tint_col, border_col);
1211 if (ImGui::BeginItemTooltip())
1212 {
1213 float region_sz = 32.0f;
1214 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1215 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1216 float zoom = 4.0f;
1217 if (region_x < 0.0f) { region_x = 0.0f; }
1218 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1219 if (region_y < 0.0f) { region_y = 0.0f; }
1220 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1221 ImGui::Text(fmt: "Min: (%.2f, %.2f)", region_x, region_y);
1222 ImGui::Text(fmt: "Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1223 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1224 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1225 ImGui::Image(user_texture_id: my_tex_id, image_size: ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
1226 ImGui::EndTooltip();
1227 }
1228 }
1229
1230 IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1231 ImGui::TextWrapped(fmt: "And now some textured buttons..");
1232 static int pressed_count = 0;
1233 for (int i = 0; i < 8; i++)
1234 {
1235 // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1236 // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1237 // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1238 ImGui::PushID(int_id: i);
1239 if (i > 0)
1240 ImGui::PushStyleVar(idx: ImGuiStyleVar_FramePadding, val: ImVec2(i - 1.0f, i - 1.0f));
1241 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
1242 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
1243 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture
1244 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
1245 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1246 if (ImGui::ImageButton(str_id: "", user_texture_id: my_tex_id, image_size: size, uv0, uv1, bg_col, tint_col))
1247 pressed_count += 1;
1248 if (i > 0)
1249 ImGui::PopStyleVar();
1250 ImGui::PopID();
1251 ImGui::SameLine();
1252 }
1253 ImGui::NewLine();
1254 ImGui::Text(fmt: "Pressed %d times.", pressed_count);
1255 ImGui::TreePop();
1256 }
1257
1258 IMGUI_DEMO_MARKER("Widgets/Combo");
1259 if (ImGui::TreeNode(label: "Combo"))
1260 {
1261 // Combo Boxes are also called "Dropdown" in other systems
1262 // Expose flags as checkbox for the demo
1263 static ImGuiComboFlags flags = 0;
1264 ImGui::CheckboxFlags(label: "ImGuiComboFlags_PopupAlignLeft", flags: &flags, flags_value: ImGuiComboFlags_PopupAlignLeft);
1265 ImGui::SameLine(); HelpMarker(desc: "Only makes a difference if the popup is larger than the combo");
1266 if (ImGui::CheckboxFlags(label: "ImGuiComboFlags_NoArrowButton", flags: &flags, flags_value: ImGuiComboFlags_NoArrowButton))
1267 flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags
1268 if (ImGui::CheckboxFlags(label: "ImGuiComboFlags_NoPreview", flags: &flags, flags_value: ImGuiComboFlags_NoPreview))
1269 flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1270 if (ImGui::CheckboxFlags(label: "ImGuiComboFlags_WidthFitPreview", flags: &flags, flags_value: ImGuiComboFlags_WidthFitPreview))
1271 flags &= ~ImGuiComboFlags_NoPreview;
1272
1273 // Override default popup height
1274 if (ImGui::CheckboxFlags(label: "ImGuiComboFlags_HeightSmall", flags: &flags, flags_value: ImGuiComboFlags_HeightSmall))
1275 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1276 if (ImGui::CheckboxFlags(label: "ImGuiComboFlags_HeightRegular", flags: &flags, flags_value: ImGuiComboFlags_HeightRegular))
1277 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1278 if (ImGui::CheckboxFlags(label: "ImGuiComboFlags_HeightLargest", flags: &flags, flags_value: ImGuiComboFlags_HeightLargest))
1279 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1280
1281 // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1282 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1283 // stored in the object itself, etc.)
1284 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1285 static int item_current_idx = 0; // Here we store our selection data as an index.
1286
1287 // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1288 const char* combo_preview_value = items[item_current_idx];
1289
1290 if (ImGui::BeginCombo(label: "combo 1", preview_value: combo_preview_value, flags))
1291 {
1292 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1293 {
1294 const bool is_selected = (item_current_idx == n);
1295 if (ImGui::Selectable(label: items[n], selected: is_selected))
1296 item_current_idx = n;
1297
1298 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1299 if (is_selected)
1300 ImGui::SetItemDefaultFocus();
1301 }
1302 ImGui::EndCombo();
1303 }
1304
1305 ImGui::Spacing();
1306 ImGui::SeparatorText(label: "One-liner variants");
1307 HelpMarker(desc: "Flags above don't apply to this section.");
1308
1309 // Simplified one-liner Combo() API, using values packed in a single constant string
1310 // This is a convenience for when the selection set is small and known at compile-time.
1311 static int item_current_2 = 0;
1312 ImGui::Combo(label: "combo 2 (one-liner)", current_item: &item_current_2, items_separated_by_zeros: "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1313
1314 // Simplified one-liner Combo() using an array of const char*
1315 // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1316 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1317 ImGui::Combo(label: "combo 3 (array)", current_item: &item_current_3, items, IM_ARRAYSIZE(items));
1318
1319 // Simplified one-liner Combo() using an accessor function
1320 static int item_current_4 = 0;
1321 ImGui::Combo(label: "combo 4 (function)", current_item: &item_current_4, getter: [](void* data, int n) { return ((const char**)data)[n]; }, user_data: items, IM_ARRAYSIZE(items));
1322
1323 ImGui::TreePop();
1324 }
1325
1326 IMGUI_DEMO_MARKER("Widgets/List Boxes");
1327 if (ImGui::TreeNode(label: "List boxes"))
1328 {
1329 // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
1330 // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
1331 // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
1332 // to always be called (inconsistent with BeginListBox()/EndListBox()).
1333
1334 // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1335 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1336 // stored in the object itself, etc.)
1337 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1338 static int item_current_idx = 0; // Here we store our selection data as an index.
1339 if (ImGui::BeginListBox(label: "listbox 1"))
1340 {
1341 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1342 {
1343 const bool is_selected = (item_current_idx == n);
1344 if (ImGui::Selectable(label: items[n], selected: is_selected))
1345 item_current_idx = n;
1346
1347 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1348 if (is_selected)
1349 ImGui::SetItemDefaultFocus();
1350 }
1351 ImGui::EndListBox();
1352 }
1353 ImGui::SameLine(); HelpMarker(desc: "Here we are sharing selection state between both boxes.");
1354
1355 // Custom size: use all width, 5 items tall
1356 ImGui::Text(fmt: "Full-width:");
1357 if (ImGui::BeginListBox(label: "##listbox 2", size: ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1358 {
1359 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1360 {
1361 const bool is_selected = (item_current_idx == n);
1362 if (ImGui::Selectable(label: items[n], selected: is_selected))
1363 item_current_idx = n;
1364
1365 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1366 if (is_selected)
1367 ImGui::SetItemDefaultFocus();
1368 }
1369 ImGui::EndListBox();
1370 }
1371
1372 ImGui::TreePop();
1373 }
1374
1375 IMGUI_DEMO_MARKER("Widgets/Selectables");
1376 if (ImGui::TreeNode(label: "Selectables"))
1377 {
1378 // Selectable() has 2 overloads:
1379 // - The one taking "bool selected" as a read-only selection information.
1380 // When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1381 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1382 // The earlier is more flexible, as in real application your selection may be stored in many different ways
1383 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1384 IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
1385 if (ImGui::TreeNode(label: "Basic"))
1386 {
1387 static bool selection[5] = { false, true, false, false };
1388 ImGui::Selectable(label: "1. I am selectable", p_selected: &selection[0]);
1389 ImGui::Selectable(label: "2. I am selectable", p_selected: &selection[1]);
1390 ImGui::Selectable(label: "3. I am selectable", p_selected: &selection[2]);
1391 if (ImGui::Selectable(label: "4. I am double clickable", selected: selection[3], flags: ImGuiSelectableFlags_AllowDoubleClick))
1392 if (ImGui::IsMouseDoubleClicked(button: 0))
1393 selection[3] = !selection[3];
1394 ImGui::TreePop();
1395 }
1396
1397 IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection");
1398 if (ImGui::TreeNode(label: "Selection State: Single Selection"))
1399 {
1400 static int selected = -1;
1401 for (int n = 0; n < 5; n++)
1402 {
1403 char buf[32];
1404 sprintf(s: buf, format: "Object %d", n);
1405 if (ImGui::Selectable(label: buf, selected: selected == n))
1406 selected = n;
1407 }
1408 ImGui::TreePop();
1409 }
1410 IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple Selection");
1411 if (ImGui::TreeNode(label: "Selection State: Multiple Selection"))
1412 {
1413 HelpMarker(desc: "Hold CTRL and click to select multiple items.");
1414 static bool selection[5] = { false, false, false, false, false };
1415 for (int n = 0; n < 5; n++)
1416 {
1417 char buf[32];
1418 sprintf(s: buf, format: "Object %d", n);
1419 if (ImGui::Selectable(label: buf, selected: selection[n]))
1420 {
1421 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
1422 memset(s: selection, c: 0, n: sizeof(selection));
1423 selection[n] ^= 1;
1424 }
1425 }
1426 ImGui::TreePop();
1427 }
1428 IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
1429 if (ImGui::TreeNode(label: "Rendering more items on the same line"))
1430 {
1431 // (1) Using SetNextItemAllowOverlap()
1432 // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
1433 static bool selected[3] = { false, false, false };
1434 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable(label: "main.c", p_selected: &selected[0]); ImGui::SameLine(); ImGui::SmallButton(label: "Link 1");
1435 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable(label: "Hello.cpp", p_selected: &selected[1]); ImGui::SameLine(); ImGui::SmallButton(label: "Link 2");
1436 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable(label: "Hello.h", p_selected: &selected[2]); ImGui::SameLine(); ImGui::SmallButton(label: "Link 3");
1437 ImGui::TreePop();
1438 }
1439
1440 IMGUI_DEMO_MARKER("Widgets/Selectables/In columns");
1441 if (ImGui::TreeNode(label: "In columns"))
1442 {
1443 static bool selected[10] = {};
1444
1445 if (ImGui::BeginTable(str_id: "split1", column: 3, flags: ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1446 {
1447 for (int i = 0; i < 10; i++)
1448 {
1449 char label[32];
1450 sprintf(s: label, format: "Item %d", i);
1451 ImGui::TableNextColumn();
1452 ImGui::Selectable(label, p_selected: &selected[i]); // FIXME-TABLE: Selection overlap
1453 }
1454 ImGui::EndTable();
1455 }
1456 ImGui::Spacing();
1457 if (ImGui::BeginTable(str_id: "split2", column: 3, flags: ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1458 {
1459 for (int i = 0; i < 10; i++)
1460 {
1461 char label[32];
1462 sprintf(s: label, format: "Item %d", i);
1463 ImGui::TableNextRow();
1464 ImGui::TableNextColumn();
1465 ImGui::Selectable(label, p_selected: &selected[i], flags: ImGuiSelectableFlags_SpanAllColumns);
1466 ImGui::TableNextColumn();
1467 ImGui::Text(fmt: "Some other contents");
1468 ImGui::TableNextColumn();
1469 ImGui::Text(fmt: "123456");
1470 }
1471 ImGui::EndTable();
1472 }
1473 ImGui::TreePop();
1474 }
1475
1476 IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
1477 if (ImGui::TreeNode(label: "Grid"))
1478 {
1479 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
1480
1481 // Add in a bit of silly fun...
1482 const float time = (float)ImGui::GetTime();
1483 const bool winning_state = memchr(s: selected, c: 0, n: sizeof(selected)) == NULL; // If all cells are selected...
1484 if (winning_state)
1485 ImGui::PushStyleVar(idx: ImGuiStyleVar_SelectableTextAlign, val: ImVec2(0.5f + 0.5f * cosf(x: time * 2.0f), 0.5f + 0.5f * sinf(x: time * 3.0f)));
1486
1487 for (int y = 0; y < 4; y++)
1488 for (int x = 0; x < 4; x++)
1489 {
1490 if (x > 0)
1491 ImGui::SameLine();
1492 ImGui::PushID(int_id: y * 4 + x);
1493 if (ImGui::Selectable(label: "Sailor", selected: selected[y][x] != 0, flags: 0, size: ImVec2(50, 50)))
1494 {
1495 // Toggle clicked cell + toggle neighbors
1496 selected[y][x] ^= 1;
1497 if (x > 0) { selected[y][x - 1] ^= 1; }
1498 if (x < 3) { selected[y][x + 1] ^= 1; }
1499 if (y > 0) { selected[y - 1][x] ^= 1; }
1500 if (y < 3) { selected[y + 1][x] ^= 1; }
1501 }
1502 ImGui::PopID();
1503 }
1504
1505 if (winning_state)
1506 ImGui::PopStyleVar();
1507 ImGui::TreePop();
1508 }
1509 IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
1510 if (ImGui::TreeNode(label: "Alignment"))
1511 {
1512 HelpMarker(
1513 desc: "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1514 "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1515 "left-align otherwise it becomes difficult to layout multiple items on a same line");
1516 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1517 for (int y = 0; y < 3; y++)
1518 {
1519 for (int x = 0; x < 3; x++)
1520 {
1521 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1522 char name[32];
1523 sprintf(s: name, format: "(%.1f,%.1f)", alignment.x, alignment.y);
1524 if (x > 0) ImGui::SameLine();
1525 ImGui::PushStyleVar(idx: ImGuiStyleVar_SelectableTextAlign, val: alignment);
1526 ImGui::Selectable(label: name, p_selected: &selected[3 * y + x], flags: ImGuiSelectableFlags_None, size: ImVec2(80, 80));
1527 ImGui::PopStyleVar();
1528 }
1529 }
1530 ImGui::TreePop();
1531 }
1532 ImGui::TreePop();
1533 }
1534
1535 // To wire InputText() with std::string or any other custom string type,
1536 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1537 IMGUI_DEMO_MARKER("Widgets/Text Input");
1538 if (ImGui::TreeNode(label: "Text Input"))
1539 {
1540 IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
1541 if (ImGui::TreeNode(label: "Multi-line Text Input"))
1542 {
1543 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1544 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1545 static char text[1024 * 16] =
1546 "/*\n"
1547 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1548 " the hexadecimal encoding of one offending instruction,\n"
1549 " more formally, the invalid operand with locked CMPXCHG8B\n"
1550 " instruction bug, is a design flaw in the majority of\n"
1551 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1552 " processors (all in the P5 microarchitecture).\n"
1553 "*/\n\n"
1554 "label:\n"
1555 "\tlock cmpxchg8b eax\n";
1556
1557 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1558 HelpMarker(desc: "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)");
1559 ImGui::CheckboxFlags(label: "ImGuiInputTextFlags_ReadOnly", flags: &flags, flags_value: ImGuiInputTextFlags_ReadOnly);
1560 ImGui::CheckboxFlags(label: "ImGuiInputTextFlags_AllowTabInput", flags: &flags, flags_value: ImGuiInputTextFlags_AllowTabInput);
1561 ImGui::SameLine(); HelpMarker(desc: "When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.");
1562 ImGui::CheckboxFlags(label: "ImGuiInputTextFlags_CtrlEnterForNewLine", flags: &flags, flags_value: ImGuiInputTextFlags_CtrlEnterForNewLine);
1563 ImGui::InputTextMultiline(label: "##source", buf: text, IM_ARRAYSIZE(text), size: ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1564 ImGui::TreePop();
1565 }
1566
1567 IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
1568 if (ImGui::TreeNode(label: "Filtered Text Input"))
1569 {
1570 struct TextFilters
1571 {
1572 // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
1573 static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
1574 {
1575 if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
1576 else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
1577 return 0;
1578 }
1579
1580 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
1581 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1582 {
1583 if (data->EventChar < 256 && strchr(s: "imgui", c: (char)data->EventChar))
1584 return 0;
1585 return 1;
1586 }
1587 };
1588
1589 static char buf1[32] = ""; ImGui::InputText(label: "default", buf: buf1, buf_size: 32);
1590 static char buf2[32] = ""; ImGui::InputText(label: "decimal", buf: buf2, buf_size: 32, flags: ImGuiInputTextFlags_CharsDecimal);
1591 static char buf3[32] = ""; ImGui::InputText(label: "hexadecimal", buf: buf3, buf_size: 32, flags: ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1592 static char buf4[32] = ""; ImGui::InputText(label: "uppercase", buf: buf4, buf_size: 32, flags: ImGuiInputTextFlags_CharsUppercase);
1593 static char buf5[32] = ""; ImGui::InputText(label: "no blank", buf: buf5, buf_size: 32, flags: ImGuiInputTextFlags_CharsNoBlank);
1594 static char buf6[32] = ""; ImGui::InputText(label: "casing swap", buf: buf6, buf_size: 32, flags: ImGuiInputTextFlags_CallbackCharFilter, callback: TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
1595 static char buf7[32] = ""; ImGui::InputText(label: "\"imgui\"", buf: buf7, buf_size: 32, flags: ImGuiInputTextFlags_CallbackCharFilter, callback: TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
1596 ImGui::TreePop();
1597 }
1598
1599 IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
1600 if (ImGui::TreeNode(label: "Password Input"))
1601 {
1602 static char password[64] = "password123";
1603 ImGui::InputText(label: "password", buf: password, IM_ARRAYSIZE(password), flags: ImGuiInputTextFlags_Password);
1604 ImGui::SameLine(); HelpMarker(desc: "Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1605 ImGui::InputTextWithHint(label: "password (w/ hint)", hint: "<password>", buf: password, IM_ARRAYSIZE(password), flags: ImGuiInputTextFlags_Password);
1606 ImGui::InputText(label: "password (clear)", buf: password, IM_ARRAYSIZE(password));
1607 ImGui::TreePop();
1608 }
1609
1610 IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
1611 if (ImGui::TreeNode(label: "Completion, History, Edit Callbacks"))
1612 {
1613 struct Funcs
1614 {
1615 static int MyCallback(ImGuiInputTextCallbackData* data)
1616 {
1617 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1618 {
1619 data->InsertChars(pos: data->CursorPos, text: "..");
1620 }
1621 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1622 {
1623 if (data->EventKey == ImGuiKey_UpArrow)
1624 {
1625 data->DeleteChars(pos: 0, bytes_count: data->BufTextLen);
1626 data->InsertChars(pos: 0, text: "Pressed Up!");
1627 data->SelectAll();
1628 }
1629 else if (data->EventKey == ImGuiKey_DownArrow)
1630 {
1631 data->DeleteChars(pos: 0, bytes_count: data->BufTextLen);
1632 data->InsertChars(pos: 0, text: "Pressed Down!");
1633 data->SelectAll();
1634 }
1635 }
1636 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1637 {
1638 // Toggle casing of first character
1639 char c = data->Buf[0];
1640 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1641 data->BufDirty = true;
1642
1643 // Increment a counter
1644 int* p_int = (int*)data->UserData;
1645 *p_int = *p_int + 1;
1646 }
1647 return 0;
1648 }
1649 };
1650 static char buf1[64];
1651 ImGui::InputText(label: "Completion", buf: buf1, buf_size: 64, flags: ImGuiInputTextFlags_CallbackCompletion, callback: Funcs::MyCallback);
1652 ImGui::SameLine(); HelpMarker(
1653 desc: "Here we append \"..\" each time Tab is pressed. "
1654 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1655
1656 static char buf2[64];
1657 ImGui::InputText(label: "History", buf: buf2, buf_size: 64, flags: ImGuiInputTextFlags_CallbackHistory, callback: Funcs::MyCallback);
1658 ImGui::SameLine(); HelpMarker(
1659 desc: "Here we replace and select text each time Up/Down are pressed. "
1660 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1661
1662 static char buf3[64];
1663 static int edit_count = 0;
1664 ImGui::InputText(label: "Edit", buf: buf3, buf_size: 64, flags: ImGuiInputTextFlags_CallbackEdit, callback: Funcs::MyCallback, user_data: (void*)&edit_count);
1665 ImGui::SameLine(); HelpMarker(
1666 desc: "Here we toggle the casing of the first character on every edit + count edits.");
1667 ImGui::SameLine(); ImGui::Text(fmt: "(%d)", edit_count);
1668
1669 ImGui::TreePop();
1670 }
1671
1672 IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
1673 if (ImGui::TreeNode(label: "Resize Callback"))
1674 {
1675 // To wire InputText() with std::string or any other custom string type,
1676 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1677 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1678 HelpMarker(
1679 desc: "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1680 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1681 struct Funcs
1682 {
1683 static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1684 {
1685 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1686 {
1687 ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1688 IM_ASSERT(my_str->begin() == data->Buf);
1689 my_str->resize(new_size: data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1690 data->Buf = my_str->begin();
1691 }
1692 return 0;
1693 }
1694
1695 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1696 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1697 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1698 {
1699 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1700 return ImGui::InputTextMultiline(label, buf: my_str->begin(), buf_size: (size_t)my_str->size(), size, flags: flags | ImGuiInputTextFlags_CallbackResize, callback: Funcs::MyResizeCallback, user_data: (void*)my_str);
1701 }
1702 };
1703
1704 // For this demo we are using ImVector as a string container.
1705 // Note that because we need to store a terminating zero character, our size/capacity are 1 more
1706 // than usually reported by a typical string class.
1707 static ImVector<char> my_str;
1708 if (my_str.empty())
1709 my_str.push_back(v: 0);
1710 Funcs::MyInputTextMultiline(label: "##MyStr", my_str: &my_str, size: ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1711 ImGui::Text(fmt: "Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1712 ImGui::TreePop();
1713 }
1714
1715 IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
1716 if (ImGui::TreeNode(label: "Miscellaneous"))
1717 {
1718 static char buf1[16];
1719 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
1720 ImGui::CheckboxFlags(label: "ImGuiInputTextFlags_EscapeClearsAll", flags: &flags, flags_value: ImGuiInputTextFlags_EscapeClearsAll);
1721 ImGui::CheckboxFlags(label: "ImGuiInputTextFlags_ReadOnly", flags: &flags, flags_value: ImGuiInputTextFlags_ReadOnly);
1722 ImGui::CheckboxFlags(label: "ImGuiInputTextFlags_NoUndoRedo", flags: &flags, flags_value: ImGuiInputTextFlags_NoUndoRedo);
1723 ImGui::InputText(label: "Hello", buf: buf1, IM_ARRAYSIZE(buf1), flags);
1724 ImGui::TreePop();
1725 }
1726
1727 ImGui::TreePop();
1728 }
1729
1730 // Tabs
1731 IMGUI_DEMO_MARKER("Widgets/Tabs");
1732 if (ImGui::TreeNode(label: "Tabs"))
1733 {
1734 IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
1735 if (ImGui::TreeNode(label: "Basic"))
1736 {
1737 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1738 if (ImGui::BeginTabBar(str_id: "MyTabBar", flags: tab_bar_flags))
1739 {
1740 if (ImGui::BeginTabItem(label: "Avocado"))
1741 {
1742 ImGui::Text(fmt: "This is the Avocado tab!\nblah blah blah blah blah");
1743 ImGui::EndTabItem();
1744 }
1745 if (ImGui::BeginTabItem(label: "Broccoli"))
1746 {
1747 ImGui::Text(fmt: "This is the Broccoli tab!\nblah blah blah blah blah");
1748 ImGui::EndTabItem();
1749 }
1750 if (ImGui::BeginTabItem(label: "Cucumber"))
1751 {
1752 ImGui::Text(fmt: "This is the Cucumber tab!\nblah blah blah blah blah");
1753 ImGui::EndTabItem();
1754 }
1755 ImGui::EndTabBar();
1756 }
1757 ImGui::Separator();
1758 ImGui::TreePop();
1759 }
1760
1761 IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
1762 if (ImGui::TreeNode(label: "Advanced & Close Button"))
1763 {
1764 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1765 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1766 ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_Reorderable", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_Reorderable);
1767 ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_AutoSelectNewTabs", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_AutoSelectNewTabs);
1768 ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_TabListPopupButton", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_TabListPopupButton);
1769 ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1770 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1771 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1772 if (ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_FittingPolicyResizeDown", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_FittingPolicyResizeDown))
1773 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1774 if (ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_FittingPolicyScroll", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_FittingPolicyScroll))
1775 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1776
1777 // Tab Bar
1778 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1779 static bool opened[4] = { true, true, true, true }; // Persistent user state
1780 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1781 {
1782 if (n > 0) { ImGui::SameLine(); }
1783 ImGui::Checkbox(label: names[n], v: &opened[n]);
1784 }
1785
1786 // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
1787 // the underlying bool will be set to false when the tab is closed.
1788 if (ImGui::BeginTabBar(str_id: "MyTabBar", flags: tab_bar_flags))
1789 {
1790 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1791 if (opened[n] && ImGui::BeginTabItem(label: names[n], p_open: &opened[n], flags: ImGuiTabItemFlags_None))
1792 {
1793 ImGui::Text(fmt: "This is the %s tab!", names[n]);
1794 if (n & 1)
1795 ImGui::Text(fmt: "I am an odd tab.");
1796 ImGui::EndTabItem();
1797 }
1798 ImGui::EndTabBar();
1799 }
1800 ImGui::Separator();
1801 ImGui::TreePop();
1802 }
1803
1804 IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
1805 if (ImGui::TreeNode(label: "TabItemButton & Leading/Trailing flags"))
1806 {
1807 static ImVector<int> active_tabs;
1808 static int next_tab_id = 0;
1809 if (next_tab_id == 0) // Initialize with some default tabs
1810 for (int i = 0; i < 3; i++)
1811 active_tabs.push_back(v: next_tab_id++);
1812
1813 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
1814 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
1815 // but they tend to make more sense together)
1816 static bool show_leading_button = true;
1817 static bool show_trailing_button = true;
1818 ImGui::Checkbox(label: "Show Leading TabItemButton()", v: &show_leading_button);
1819 ImGui::Checkbox(label: "Show Trailing TabItemButton()", v: &show_trailing_button);
1820
1821 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
1822 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
1823 ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_TabListPopupButton", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_TabListPopupButton);
1824 if (ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_FittingPolicyResizeDown", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_FittingPolicyResizeDown))
1825 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1826 if (ImGui::CheckboxFlags(label: "ImGuiTabBarFlags_FittingPolicyScroll", flags: &tab_bar_flags, flags_value: ImGuiTabBarFlags_FittingPolicyScroll))
1827 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1828
1829 if (ImGui::BeginTabBar(str_id: "MyTabBar", flags: tab_bar_flags))
1830 {
1831 // Demo a Leading TabItemButton(): click the "?" button to open a menu
1832 if (show_leading_button)
1833 if (ImGui::TabItemButton(label: "?", flags: ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
1834 ImGui::OpenPopup(str_id: "MyHelpMenu");
1835 if (ImGui::BeginPopup(str_id: "MyHelpMenu"))
1836 {
1837 ImGui::Selectable(label: "Hello!");
1838 ImGui::EndPopup();
1839 }
1840
1841 // Demo Trailing Tabs: click the "+" button to add a new tab.
1842 // (In your app you may want to use a font icon instead of the "+")
1843 // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
1844 if (show_trailing_button)
1845 if (ImGui::TabItemButton(label: "+", flags: ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
1846 active_tabs.push_back(v: next_tab_id++); // Add new tab
1847
1848 // Submit our regular tabs
1849 for (int n = 0; n < active_tabs.Size; )
1850 {
1851 bool open = true;
1852 char name[16];
1853 snprintf(s: name, IM_ARRAYSIZE(name), format: "%04d", active_tabs[n]);
1854 if (ImGui::BeginTabItem(label: name, p_open: &open, flags: ImGuiTabItemFlags_None))
1855 {
1856 ImGui::Text(fmt: "This is the %s tab!", name);
1857 ImGui::EndTabItem();
1858 }
1859
1860 if (!open)
1861 active_tabs.erase(it: active_tabs.Data + n);
1862 else
1863 n++;
1864 }
1865
1866 ImGui::EndTabBar();
1867 }
1868 ImGui::Separator();
1869 ImGui::TreePop();
1870 }
1871 ImGui::TreePop();
1872 }
1873
1874 // Plot/Graph widgets are not very good.
1875 // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
1876 // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
1877 IMGUI_DEMO_MARKER("Widgets/Plotting");
1878 if (ImGui::TreeNode(label: "Plotting"))
1879 {
1880 static bool animate = true;
1881 ImGui::Checkbox(label: "Animate", v: &animate);
1882
1883 // Plot as lines and plot as histogram
1884 IMGUI_DEMO_MARKER("Widgets/Plotting/PlotLines, PlotHistogram");
1885 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1886 ImGui::PlotLines(label: "Frame Times", values: arr, IM_ARRAYSIZE(arr));
1887 ImGui::PlotHistogram(label: "Histogram", values: arr, IM_ARRAYSIZE(arr), values_offset: 0, NULL, scale_min: 0.0f, scale_max: 1.0f, graph_size: ImVec2(0, 80.0f));
1888 //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!");
1889
1890 // Fill an array of contiguous float values to plot
1891 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
1892 // and the sizeof() of your structure in the "stride" parameter.
1893 static float values[90] = {};
1894 static int values_offset = 0;
1895 static double refresh_time = 0.0;
1896 if (!animate || refresh_time == 0.0)
1897 refresh_time = ImGui::GetTime();
1898 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
1899 {
1900 static float phase = 0.0f;
1901 values[values_offset] = cosf(x: phase);
1902 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
1903 phase += 0.10f * values_offset;
1904 refresh_time += 1.0f / 60.0f;
1905 }
1906
1907 // Plots can display overlay texts
1908 // (in this example, we will display an average value)
1909 {
1910 float average = 0.0f;
1911 for (int n = 0; n < IM_ARRAYSIZE(values); n++)
1912 average += values[n];
1913 average /= (float)IM_ARRAYSIZE(values);
1914 char overlay[32];
1915 sprintf(s: overlay, format: "avg %f", average);
1916 ImGui::PlotLines(label: "Lines", values, IM_ARRAYSIZE(values), values_offset, overlay_text: overlay, scale_min: -1.0f, scale_max: 1.0f, graph_size: ImVec2(0, 80.0f));
1917 }
1918
1919 // Use functions to generate output
1920 // FIXME: This is actually VERY awkward because current plot API only pass in indices.
1921 // We probably want an API passing floats and user provide sample rate/count.
1922 struct Funcs
1923 {
1924 static float Sin(void*, int i) { return sinf(x: i * 0.1f); }
1925 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
1926 };
1927 static int func_type = 0, display_count = 70;
1928 ImGui::SeparatorText(label: "Functions");
1929 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
1930 ImGui::Combo(label: "func", current_item: &func_type, items_separated_by_zeros: "Sin\0Saw\0");
1931 ImGui::SameLine();
1932 ImGui::SliderInt(label: "Sample count", v: &display_count, v_min: 1, v_max: 400);
1933 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
1934 ImGui::PlotLines(label: "Lines", values_getter: func, NULL, values_count: display_count, values_offset: 0, NULL, scale_min: -1.0f, scale_max: 1.0f, graph_size: ImVec2(0, 80));
1935 ImGui::PlotHistogram(label: "Histogram", values_getter: func, NULL, values_count: display_count, values_offset: 0, NULL, scale_min: -1.0f, scale_max: 1.0f, graph_size: ImVec2(0, 80));
1936 ImGui::Separator();
1937
1938 // Animate a simple progress bar
1939 IMGUI_DEMO_MARKER("Widgets/Plotting/ProgressBar");
1940 static float progress = 0.0f, progress_dir = 1.0f;
1941 if (animate)
1942 {
1943 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
1944 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
1945 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
1946 }
1947
1948 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
1949 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
1950 ImGui::ProgressBar(fraction: progress, size_arg: ImVec2(0.0f, 0.0f));
1951 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: ImGui::GetStyle().ItemInnerSpacing.x);
1952 ImGui::Text(fmt: "Progress Bar");
1953
1954 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
1955 char buf[32];
1956 sprintf(s: buf, format: "%d/%d", (int)(progress_saturated * 1753), 1753);
1957 ImGui::ProgressBar(fraction: progress, size_arg: ImVec2(0.f, 0.f), overlay: buf);
1958 ImGui::TreePop();
1959 }
1960
1961 IMGUI_DEMO_MARKER("Widgets/Color");
1962 if (ImGui::TreeNode(label: "Color/Picker Widgets"))
1963 {
1964 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
1965
1966 static bool alpha_preview = true;
1967 static bool alpha_half_preview = false;
1968 static bool drag_and_drop = true;
1969 static bool options_menu = true;
1970 static bool hdr = false;
1971 ImGui::SeparatorText(label: "Options");
1972 ImGui::Checkbox(label: "With Alpha Preview", v: &alpha_preview);
1973 ImGui::Checkbox(label: "With Half Alpha Preview", v: &alpha_half_preview);
1974 ImGui::Checkbox(label: "With Drag and Drop", v: &drag_and_drop);
1975 ImGui::Checkbox(label: "With Options Menu", v: &options_menu); ImGui::SameLine(); HelpMarker(desc: "Right-click on the individual color widget to show options.");
1976 ImGui::Checkbox(label: "With HDR", v: &hdr); ImGui::SameLine(); HelpMarker(desc: "Currently all this does is to lift the 0..1 limits on dragging widgets.");
1977 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);
1978
1979 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
1980 ImGui::SeparatorText(label: "Inline color editor");
1981 ImGui::Text(fmt: "Color widget:");
1982 ImGui::SameLine(); HelpMarker(
1983 desc: "Click on the color square to open a color picker.\n"
1984 "CTRL+click on individual component to input value.\n");
1985 ImGui::ColorEdit3(label: "MyColor##1", col: (float*)&color, flags: misc_flags);
1986
1987 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
1988 ImGui::Text(fmt: "Color widget HSV with Alpha:");
1989 ImGui::ColorEdit4(label: "MyColor##2", col: (float*)&color, flags: ImGuiColorEditFlags_DisplayHSV | misc_flags);
1990
1991 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
1992 ImGui::Text(fmt: "Color widget with Float Display:");
1993 ImGui::ColorEdit4(label: "MyColor##2f", col: (float*)&color, flags: ImGuiColorEditFlags_Float | misc_flags);
1994
1995 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
1996 ImGui::Text(fmt: "Color button with Picker:");
1997 ImGui::SameLine(); HelpMarker(
1998 desc: "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
1999 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
2000 "be used for the tooltip and picker popup.");
2001 ImGui::ColorEdit4(label: "MyColor##3", col: (float*)&color, flags: ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
2002
2003 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
2004 ImGui::Text(fmt: "Color button with Custom Picker Popup:");
2005
2006 // Generate a default palette. The palette will persist and can be edited.
2007 static bool saved_palette_init = true;
2008 static ImVec4 saved_palette[32] = {};
2009 if (saved_palette_init)
2010 {
2011 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2012 {
2013 ImGui::ColorConvertHSVtoRGB(h: n / 31.0f, s: 0.8f, v: 0.8f,
2014 out_r&: saved_palette[n].x, out_g&: saved_palette[n].y, out_b&: saved_palette[n].z);
2015 saved_palette[n].w = 1.0f; // Alpha
2016 }
2017 saved_palette_init = false;
2018 }
2019
2020 static ImVec4 backup_color;
2021 bool open_popup = ImGui::ColorButton(desc_id: "MyColor##3b", col: color, flags: misc_flags);
2022 ImGui::SameLine(offset_from_start_x: 0, spacing: ImGui::GetStyle().ItemInnerSpacing.x);
2023 open_popup |= ImGui::Button(label: "Palette");
2024 if (open_popup)
2025 {
2026 ImGui::OpenPopup(str_id: "mypicker");
2027 backup_color = color;
2028 }
2029 if (ImGui::BeginPopup(str_id: "mypicker"))
2030 {
2031 ImGui::Text(fmt: "MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
2032 ImGui::Separator();
2033 ImGui::ColorPicker4(label: "##picker", col: (float*)&color, flags: misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
2034 ImGui::SameLine();
2035
2036 ImGui::BeginGroup(); // Lock X position
2037 ImGui::Text(fmt: "Current");
2038 ImGui::ColorButton(desc_id: "##current", col: color, flags: ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, size: ImVec2(60, 40));
2039 ImGui::Text(fmt: "Previous");
2040 if (ImGui::ColorButton(desc_id: "##previous", col: backup_color, flags: ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, size: ImVec2(60, 40)))
2041 color = backup_color;
2042 ImGui::Separator();
2043 ImGui::Text(fmt: "Palette");
2044 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2045 {
2046 ImGui::PushID(int_id: n);
2047 if ((n % 8) != 0)
2048 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: ImGui::GetStyle().ItemSpacing.y);
2049
2050 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
2051 if (ImGui::ColorButton(desc_id: "##palette", col: saved_palette[n], flags: palette_button_flags, size: ImVec2(20, 20)))
2052 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
2053
2054 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
2055 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
2056 if (ImGui::BeginDragDropTarget())
2057 {
2058 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
2059 memcpy(dest: (float*)&saved_palette[n], src: payload->Data, n: sizeof(float) * 3);
2060 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
2061 memcpy(dest: (float*)&saved_palette[n], src: payload->Data, n: sizeof(float) * 4);
2062 ImGui::EndDragDropTarget();
2063 }
2064
2065 ImGui::PopID();
2066 }
2067 ImGui::EndGroup();
2068 ImGui::EndPopup();
2069 }
2070
2071 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
2072 ImGui::Text(fmt: "Color button only:");
2073 static bool no_border = false;
2074 ImGui::Checkbox(label: "ImGuiColorEditFlags_NoBorder", v: &no_border);
2075 ImGui::ColorButton(desc_id: "MyColor##3c", col: *(ImVec4*)&color, flags: misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), size: ImVec2(80, 80));
2076
2077 IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
2078 ImGui::SeparatorText(label: "Color picker");
2079 static bool alpha = true;
2080 static bool alpha_bar = true;
2081 static bool side_preview = true;
2082 static bool ref_color = false;
2083 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
2084 static int display_mode = 0;
2085 static int picker_mode = 0;
2086 ImGui::Checkbox(label: "With Alpha", v: &alpha);
2087 ImGui::Checkbox(label: "With Alpha Bar", v: &alpha_bar);
2088 ImGui::Checkbox(label: "With Side Preview", v: &side_preview);
2089 if (side_preview)
2090 {
2091 ImGui::SameLine();
2092 ImGui::Checkbox(label: "With Ref Color", v: &ref_color);
2093 if (ref_color)
2094 {
2095 ImGui::SameLine();
2096 ImGui::ColorEdit4(label: "##RefColor", col: &ref_color_v.x, flags: ImGuiColorEditFlags_NoInputs | misc_flags);
2097 }
2098 }
2099 ImGui::Combo(label: "Display Mode", current_item: &display_mode, items_separated_by_zeros: "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
2100 ImGui::SameLine(); HelpMarker(
2101 desc: "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
2102 "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
2103 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
2104 ImGui::SameLine(); HelpMarker(desc: "When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
2105 ImGuiColorEditFlags flags = misc_flags;
2106 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
2107 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
2108 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
2109 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
2110 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
2111 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
2112 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
2113 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
2114 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
2115 ImGui::ColorPicker4(label: "MyColor##4", col: (float*)&color, flags, ref_col: ref_color ? &ref_color_v.x : NULL);
2116
2117 ImGui::Text(fmt: "Set defaults in code:");
2118 ImGui::SameLine(); HelpMarker(
2119 desc: "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
2120 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
2121 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
2122 "encouraging you to persistently save values that aren't forward-compatible.");
2123 if (ImGui::Button(label: "Default: Uint8 + HSV + Hue Bar"))
2124 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
2125 if (ImGui::Button(label: "Default: Float + HDR + Hue Wheel"))
2126 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
2127
2128 // Always display a small version of both types of pickers
2129 // (that's in order to make it more visible in the demo to people who are skimming quickly through it)
2130 ImGui::Text(fmt: "Both types:");
2131 float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
2132 ImGui::SetNextItemWidth(w);
2133 ImGui::ColorPicker3(label: "##MyColor##5", col: (float*)&color, flags: ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2134 ImGui::SameLine();
2135 ImGui::SetNextItemWidth(w);
2136 ImGui::ColorPicker3(label: "##MyColor##6", col: (float*)&color, flags: ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2137
2138 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
2139 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
2140 ImGui::Spacing();
2141 ImGui::Text(fmt: "HSV encoded colors");
2142 ImGui::SameLine(); HelpMarker(
2143 desc: "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
2144 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
2145 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
2146 ImGui::Text(fmt: "Color widget with InputHSV:");
2147 ImGui::ColorEdit4(label: "HSV shown as RGB##1", col: (float*)&color_hsv, flags: ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2148 ImGui::ColorEdit4(label: "HSV shown as HSV##1", col: (float*)&color_hsv, flags: ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2149 ImGui::DragFloat4(label: "Raw HSV values", v: (float*)&color_hsv, v_speed: 0.01f, v_min: 0.0f, v_max: 1.0f);
2150
2151 ImGui::TreePop();
2152 }
2153
2154 IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
2155 if (ImGui::TreeNode(label: "Drag/Slider Flags"))
2156 {
2157 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
2158 static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
2159 ImGui::CheckboxFlags(label: "ImGuiSliderFlags_AlwaysClamp", flags: &flags, flags_value: ImGuiSliderFlags_AlwaysClamp);
2160 ImGui::SameLine(); HelpMarker(desc: "Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
2161 ImGui::CheckboxFlags(label: "ImGuiSliderFlags_Logarithmic", flags: &flags, flags_value: ImGuiSliderFlags_Logarithmic);
2162 ImGui::SameLine(); HelpMarker(desc: "Enable logarithmic editing (more precision for small values).");
2163 ImGui::CheckboxFlags(label: "ImGuiSliderFlags_NoRoundToFormat", flags: &flags, flags_value: ImGuiSliderFlags_NoRoundToFormat);
2164 ImGui::SameLine(); HelpMarker(desc: "Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
2165 ImGui::CheckboxFlags(label: "ImGuiSliderFlags_NoInput", flags: &flags, flags_value: ImGuiSliderFlags_NoInput);
2166 ImGui::SameLine(); HelpMarker(desc: "Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
2167
2168 // Drags
2169 static float drag_f = 0.5f;
2170 static int drag_i = 50;
2171 ImGui::Text(fmt: "Underlying float value: %f", drag_f);
2172 ImGui::DragFloat(label: "DragFloat (0 -> 1)", v: &drag_f, v_speed: 0.005f, v_min: 0.0f, v_max: 1.0f, format: "%.3f", flags);
2173 ImGui::DragFloat(label: "DragFloat (0 -> +inf)", v: &drag_f, v_speed: 0.005f, v_min: 0.0f, FLT_MAX, format: "%.3f", flags);
2174 ImGui::DragFloat(label: "DragFloat (-inf -> 1)", v: &drag_f, v_speed: 0.005f, v_min: -FLT_MAX, v_max: 1.0f, format: "%.3f", flags);
2175 ImGui::DragFloat(label: "DragFloat (-inf -> +inf)", v: &drag_f, v_speed: 0.005f, v_min: -FLT_MAX, v_max: +FLT_MAX, format: "%.3f", flags);
2176 ImGui::DragInt(label: "DragInt (0 -> 100)", v: &drag_i, v_speed: 0.5f, v_min: 0, v_max: 100, format: "%d", flags);
2177
2178 // Sliders
2179 static float slider_f = 0.5f;
2180 static int slider_i = 50;
2181 ImGui::Text(fmt: "Underlying float value: %f", slider_f);
2182 ImGui::SliderFloat(label: "SliderFloat (0 -> 1)", v: &slider_f, v_min: 0.0f, v_max: 1.0f, format: "%.3f", flags);
2183 ImGui::SliderInt(label: "SliderInt (0 -> 100)", v: &slider_i, v_min: 0, v_max: 100, format: "%d", flags);
2184
2185 ImGui::TreePop();
2186 }
2187
2188 IMGUI_DEMO_MARKER("Widgets/Range Widgets");
2189 if (ImGui::TreeNode(label: "Range Widgets"))
2190 {
2191 static float begin = 10, end = 90;
2192 static int begin_i = 100, end_i = 1000;
2193 ImGui::DragFloatRange2(label: "range float", v_current_min: &begin, v_current_max: &end, v_speed: 0.25f, v_min: 0.0f, v_max: 100.0f, format: "Min: %.1f %%", format_max: "Max: %.1f %%", flags: ImGuiSliderFlags_AlwaysClamp);
2194 ImGui::DragIntRange2(label: "range int", v_current_min: &begin_i, v_current_max: &end_i, v_speed: 5, v_min: 0, v_max: 1000, format: "Min: %d units", format_max: "Max: %d units");
2195 ImGui::DragIntRange2(label: "range int (no bounds)", v_current_min: &begin_i, v_current_max: &end_i, v_speed: 5, v_min: 0, v_max: 0, format: "Min: %d units", format_max: "Max: %d units");
2196 ImGui::TreePop();
2197 }
2198
2199 IMGUI_DEMO_MARKER("Widgets/Data Types");
2200 if (ImGui::TreeNode(label: "Data Types"))
2201 {
2202 // DragScalar/InputScalar/SliderScalar functions allow various data types
2203 // - signed/unsigned
2204 // - 8/16/32/64-bits
2205 // - integer/float/double
2206 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
2207 // to pass the type, and passing all arguments by pointer.
2208 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
2209 // In practice, if you frequently use a given type that is not covered by the normal API entry points,
2210 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
2211 // and then pass their address to the generic function. For example:
2212 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
2213 // {
2214 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
2215 // }
2216
2217 // Setup limits (as helper variables so we can take their address, as explained above)
2218 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
2219 #ifndef LLONG_MIN
2220 ImS64 LLONG_MIN = -9223372036854775807LL - 1;
2221 ImS64 LLONG_MAX = 9223372036854775807LL;
2222 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
2223 #endif
2224 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
2225 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
2226 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
2227 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
2228 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;
2229 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;
2230 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;
2231 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;
2232 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
2233 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
2234
2235 // State
2236 static char s8_v = 127;
2237 static ImU8 u8_v = 255;
2238 static short s16_v = 32767;
2239 static ImU16 u16_v = 65535;
2240 static ImS32 s32_v = -1;
2241 static ImU32 u32_v = (ImU32)-1;
2242 static ImS64 s64_v = -1;
2243 static ImU64 u64_v = (ImU64)-1;
2244 static float f32_v = 0.123f;
2245 static double f64_v = 90000.01234567890123456789;
2246
2247 const float drag_speed = 0.2f;
2248 static bool drag_clamp = false;
2249 IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
2250 ImGui::SeparatorText(label: "Drags");
2251 ImGui::Checkbox(label: "Clamp integers to 0..50", v: &drag_clamp);
2252 ImGui::SameLine(); HelpMarker(
2253 desc: "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
2254 "You can override the clamping limits by using CTRL+Click to input a value.");
2255 ImGui::DragScalar(label: "drag s8", data_type: ImGuiDataType_S8, p_data: &s8_v, v_speed: drag_speed, p_min: drag_clamp ? &s8_zero : NULL, p_max: drag_clamp ? &s8_fifty : NULL);
2256 ImGui::DragScalar(label: "drag u8", data_type: ImGuiDataType_U8, p_data: &u8_v, v_speed: drag_speed, p_min: drag_clamp ? &u8_zero : NULL, p_max: drag_clamp ? &u8_fifty : NULL, format: "%u ms");
2257 ImGui::DragScalar(label: "drag s16", data_type: ImGuiDataType_S16, p_data: &s16_v, v_speed: drag_speed, p_min: drag_clamp ? &s16_zero : NULL, p_max: drag_clamp ? &s16_fifty : NULL);
2258 ImGui::DragScalar(label: "drag u16", data_type: ImGuiDataType_U16, p_data: &u16_v, v_speed: drag_speed, p_min: drag_clamp ? &u16_zero : NULL, p_max: drag_clamp ? &u16_fifty : NULL, format: "%u ms");
2259 ImGui::DragScalar(label: "drag s32", data_type: ImGuiDataType_S32, p_data: &s32_v, v_speed: drag_speed, p_min: drag_clamp ? &s32_zero : NULL, p_max: drag_clamp ? &s32_fifty : NULL);
2260 ImGui::DragScalar(label: "drag s32 hex", data_type: ImGuiDataType_S32, p_data: &s32_v, v_speed: drag_speed, p_min: drag_clamp ? &s32_zero : NULL, p_max: drag_clamp ? &s32_fifty : NULL, format: "0x%08X");
2261 ImGui::DragScalar(label: "drag u32", data_type: ImGuiDataType_U32, p_data: &u32_v, v_speed: drag_speed, p_min: drag_clamp ? &u32_zero : NULL, p_max: drag_clamp ? &u32_fifty : NULL, format: "%u ms");
2262 ImGui::DragScalar(label: "drag s64", data_type: ImGuiDataType_S64, p_data: &s64_v, v_speed: drag_speed, p_min: drag_clamp ? &s64_zero : NULL, p_max: drag_clamp ? &s64_fifty : NULL);
2263 ImGui::DragScalar(label: "drag u64", data_type: ImGuiDataType_U64, p_data: &u64_v, v_speed: drag_speed, p_min: drag_clamp ? &u64_zero : NULL, p_max: drag_clamp ? &u64_fifty : NULL);
2264 ImGui::DragScalar(label: "drag float", data_type: ImGuiDataType_Float, p_data: &f32_v, v_speed: 0.005f, p_min: &f32_zero, p_max: &f32_one, format: "%f");
2265 ImGui::DragScalar(label: "drag float log", data_type: ImGuiDataType_Float, p_data: &f32_v, v_speed: 0.005f, p_min: &f32_zero, p_max: &f32_one, format: "%f", flags: ImGuiSliderFlags_Logarithmic);
2266 ImGui::DragScalar(label: "drag double", data_type: ImGuiDataType_Double, p_data: &f64_v, v_speed: 0.0005f, p_min: &f64_zero, NULL, format: "%.10f grams");
2267 ImGui::DragScalar(label: "drag double log",data_type: ImGuiDataType_Double, p_data: &f64_v, v_speed: 0.0005f, p_min: &f64_zero, p_max: &f64_one, format: "0 < %.10f < 1", flags: ImGuiSliderFlags_Logarithmic);
2268
2269 IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
2270 ImGui::SeparatorText(label: "Sliders");
2271 ImGui::SliderScalar(label: "slider s8 full", data_type: ImGuiDataType_S8, p_data: &s8_v, p_min: &s8_min, p_max: &s8_max, format: "%d");
2272 ImGui::SliderScalar(label: "slider u8 full", data_type: ImGuiDataType_U8, p_data: &u8_v, p_min: &u8_min, p_max: &u8_max, format: "%u");
2273 ImGui::SliderScalar(label: "slider s16 full", data_type: ImGuiDataType_S16, p_data: &s16_v, p_min: &s16_min, p_max: &s16_max, format: "%d");
2274 ImGui::SliderScalar(label: "slider u16 full", data_type: ImGuiDataType_U16, p_data: &u16_v, p_min: &u16_min, p_max: &u16_max, format: "%u");
2275 ImGui::SliderScalar(label: "slider s32 low", data_type: ImGuiDataType_S32, p_data: &s32_v, p_min: &s32_zero, p_max: &s32_fifty,format: "%d");
2276 ImGui::SliderScalar(label: "slider s32 high", data_type: ImGuiDataType_S32, p_data: &s32_v, p_min: &s32_hi_a, p_max: &s32_hi_b, format: "%d");
2277 ImGui::SliderScalar(label: "slider s32 full", data_type: ImGuiDataType_S32, p_data: &s32_v, p_min: &s32_min, p_max: &s32_max, format: "%d");
2278 ImGui::SliderScalar(label: "slider s32 hex", data_type: ImGuiDataType_S32, p_data: &s32_v, p_min: &s32_zero, p_max: &s32_fifty, format: "0x%04X");
2279 ImGui::SliderScalar(label: "slider u32 low", data_type: ImGuiDataType_U32, p_data: &u32_v, p_min: &u32_zero, p_max: &u32_fifty,format: "%u");
2280 ImGui::SliderScalar(label: "slider u32 high", data_type: ImGuiDataType_U32, p_data: &u32_v, p_min: &u32_hi_a, p_max: &u32_hi_b, format: "%u");
2281 ImGui::SliderScalar(label: "slider u32 full", data_type: ImGuiDataType_U32, p_data: &u32_v, p_min: &u32_min, p_max: &u32_max, format: "%u");
2282 ImGui::SliderScalar(label: "slider s64 low", data_type: ImGuiDataType_S64, p_data: &s64_v, p_min: &s64_zero, p_max: &s64_fifty,format: "%" PRId64);
2283 ImGui::SliderScalar(label: "slider s64 high", data_type: ImGuiDataType_S64, p_data: &s64_v, p_min: &s64_hi_a, p_max: &s64_hi_b, format: "%" PRId64);
2284 ImGui::SliderScalar(label: "slider s64 full", data_type: ImGuiDataType_S64, p_data: &s64_v, p_min: &s64_min, p_max: &s64_max, format: "%" PRId64);
2285 ImGui::SliderScalar(label: "slider u64 low", data_type: ImGuiDataType_U64, p_data: &u64_v, p_min: &u64_zero, p_max: &u64_fifty,format: "%" PRIu64 " ms");
2286 ImGui::SliderScalar(label: "slider u64 high", data_type: ImGuiDataType_U64, p_data: &u64_v, p_min: &u64_hi_a, p_max: &u64_hi_b, format: "%" PRIu64 " ms");
2287 ImGui::SliderScalar(label: "slider u64 full", data_type: ImGuiDataType_U64, p_data: &u64_v, p_min: &u64_min, p_max: &u64_max, format: "%" PRIu64 " ms");
2288 ImGui::SliderScalar(label: "slider float low", data_type: ImGuiDataType_Float, p_data: &f32_v, p_min: &f32_zero, p_max: &f32_one);
2289 ImGui::SliderScalar(label: "slider float low log", data_type: ImGuiDataType_Float, p_data: &f32_v, p_min: &f32_zero, p_max: &f32_one, format: "%.10f", flags: ImGuiSliderFlags_Logarithmic);
2290 ImGui::SliderScalar(label: "slider float high", data_type: ImGuiDataType_Float, p_data: &f32_v, p_min: &f32_lo_a, p_max: &f32_hi_a, format: "%e");
2291 ImGui::SliderScalar(label: "slider double low", data_type: ImGuiDataType_Double, p_data: &f64_v, p_min: &f64_zero, p_max: &f64_one, format: "%.10f grams");
2292 ImGui::SliderScalar(label: "slider double low log",data_type: ImGuiDataType_Double, p_data: &f64_v, p_min: &f64_zero, p_max: &f64_one, format: "%.10f", flags: ImGuiSliderFlags_Logarithmic);
2293 ImGui::SliderScalar(label: "slider double high", data_type: ImGuiDataType_Double, p_data: &f64_v, p_min: &f64_lo_a, p_max: &f64_hi_a, format: "%e grams");
2294
2295 ImGui::SeparatorText(label: "Sliders (reverse)");
2296 ImGui::SliderScalar(label: "slider s8 reverse", data_type: ImGuiDataType_S8, p_data: &s8_v, p_min: &s8_max, p_max: &s8_min, format: "%d");
2297 ImGui::SliderScalar(label: "slider u8 reverse", data_type: ImGuiDataType_U8, p_data: &u8_v, p_min: &u8_max, p_max: &u8_min, format: "%u");
2298 ImGui::SliderScalar(label: "slider s32 reverse", data_type: ImGuiDataType_S32, p_data: &s32_v, p_min: &s32_fifty, p_max: &s32_zero, format: "%d");
2299 ImGui::SliderScalar(label: "slider u32 reverse", data_type: ImGuiDataType_U32, p_data: &u32_v, p_min: &u32_fifty, p_max: &u32_zero, format: "%u");
2300 ImGui::SliderScalar(label: "slider s64 reverse", data_type: ImGuiDataType_S64, p_data: &s64_v, p_min: &s64_fifty, p_max: &s64_zero, format: "%" PRId64);
2301 ImGui::SliderScalar(label: "slider u64 reverse", data_type: ImGuiDataType_U64, p_data: &u64_v, p_min: &u64_fifty, p_max: &u64_zero, format: "%" PRIu64 " ms");
2302
2303 IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
2304 static bool inputs_step = true;
2305 ImGui::SeparatorText(label: "Inputs");
2306 ImGui::Checkbox(label: "Show step buttons", v: &inputs_step);
2307 ImGui::InputScalar(label: "input s8", data_type: ImGuiDataType_S8, p_data: &s8_v, p_step: inputs_step ? &s8_one : NULL, NULL, format: "%d");
2308 ImGui::InputScalar(label: "input u8", data_type: ImGuiDataType_U8, p_data: &u8_v, p_step: inputs_step ? &u8_one : NULL, NULL, format: "%u");
2309 ImGui::InputScalar(label: "input s16", data_type: ImGuiDataType_S16, p_data: &s16_v, p_step: inputs_step ? &s16_one : NULL, NULL, format: "%d");
2310 ImGui::InputScalar(label: "input u16", data_type: ImGuiDataType_U16, p_data: &u16_v, p_step: inputs_step ? &u16_one : NULL, NULL, format: "%u");
2311 ImGui::InputScalar(label: "input s32", data_type: ImGuiDataType_S32, p_data: &s32_v, p_step: inputs_step ? &s32_one : NULL, NULL, format: "%d");
2312 ImGui::InputScalar(label: "input s32 hex", data_type: ImGuiDataType_S32, p_data: &s32_v, p_step: inputs_step ? &s32_one : NULL, NULL, format: "%04X");
2313 ImGui::InputScalar(label: "input u32", data_type: ImGuiDataType_U32, p_data: &u32_v, p_step: inputs_step ? &u32_one : NULL, NULL, format: "%u");
2314 ImGui::InputScalar(label: "input u32 hex", data_type: ImGuiDataType_U32, p_data: &u32_v, p_step: inputs_step ? &u32_one : NULL, NULL, format: "%08X");
2315 ImGui::InputScalar(label: "input s64", data_type: ImGuiDataType_S64, p_data: &s64_v, p_step: inputs_step ? &s64_one : NULL);
2316 ImGui::InputScalar(label: "input u64", data_type: ImGuiDataType_U64, p_data: &u64_v, p_step: inputs_step ? &u64_one : NULL);
2317 ImGui::InputScalar(label: "input float", data_type: ImGuiDataType_Float, p_data: &f32_v, p_step: inputs_step ? &f32_one : NULL);
2318 ImGui::InputScalar(label: "input double", data_type: ImGuiDataType_Double, p_data: &f64_v, p_step: inputs_step ? &f64_one : NULL);
2319
2320 ImGui::TreePop();
2321 }
2322
2323 IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
2324 if (ImGui::TreeNode(label: "Multi-component Widgets"))
2325 {
2326 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2327 static int vec4i[4] = { 1, 5, 100, 255 };
2328
2329 ImGui::SeparatorText(label: "2-wide");
2330 ImGui::InputFloat2(label: "input float2", v: vec4f);
2331 ImGui::DragFloat2(label: "drag float2", v: vec4f, v_speed: 0.01f, v_min: 0.0f, v_max: 1.0f);
2332 ImGui::SliderFloat2(label: "slider float2", v: vec4f, v_min: 0.0f, v_max: 1.0f);
2333 ImGui::InputInt2(label: "input int2", v: vec4i);
2334 ImGui::DragInt2(label: "drag int2", v: vec4i, v_speed: 1, v_min: 0, v_max: 255);
2335 ImGui::SliderInt2(label: "slider int2", v: vec4i, v_min: 0, v_max: 255);
2336
2337 ImGui::SeparatorText(label: "3-wide");
2338 ImGui::InputFloat3(label: "input float3", v: vec4f);
2339 ImGui::DragFloat3(label: "drag float3", v: vec4f, v_speed: 0.01f, v_min: 0.0f, v_max: 1.0f);
2340 ImGui::SliderFloat3(label: "slider float3", v: vec4f, v_min: 0.0f, v_max: 1.0f);
2341 ImGui::InputInt3(label: "input int3", v: vec4i);
2342 ImGui::DragInt3(label: "drag int3", v: vec4i, v_speed: 1, v_min: 0, v_max: 255);
2343 ImGui::SliderInt3(label: "slider int3", v: vec4i, v_min: 0, v_max: 255);
2344
2345 ImGui::SeparatorText(label: "4-wide");
2346 ImGui::InputFloat4(label: "input float4", v: vec4f);
2347 ImGui::DragFloat4(label: "drag float4", v: vec4f, v_speed: 0.01f, v_min: 0.0f, v_max: 1.0f);
2348 ImGui::SliderFloat4(label: "slider float4", v: vec4f, v_min: 0.0f, v_max: 1.0f);
2349 ImGui::InputInt4(label: "input int4", v: vec4i);
2350 ImGui::DragInt4(label: "drag int4", v: vec4i, v_speed: 1, v_min: 0, v_max: 255);
2351 ImGui::SliderInt4(label: "slider int4", v: vec4i, v_min: 0, v_max: 255);
2352
2353 ImGui::TreePop();
2354 }
2355
2356 IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
2357 if (ImGui::TreeNode(label: "Vertical Sliders"))
2358 {
2359 const float spacing = 4;
2360 ImGui::PushStyleVar(idx: ImGuiStyleVar_ItemSpacing, val: ImVec2(spacing, spacing));
2361
2362 static int int_value = 0;
2363 ImGui::VSliderInt(label: "##int", size: ImVec2(18, 160), v: &int_value, v_min: 0, v_max: 5);
2364 ImGui::SameLine();
2365
2366 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
2367 ImGui::PushID(str_id: "set1");
2368 for (int i = 0; i < 7; i++)
2369 {
2370 if (i > 0) ImGui::SameLine();
2371 ImGui::PushID(int_id: i);
2372 ImGui::PushStyleColor(idx: ImGuiCol_FrameBg, col: (ImVec4)ImColor::HSV(h: i / 7.0f, s: 0.5f, v: 0.5f));
2373 ImGui::PushStyleColor(idx: ImGuiCol_FrameBgHovered, col: (ImVec4)ImColor::HSV(h: i / 7.0f, s: 0.6f, v: 0.5f));
2374 ImGui::PushStyleColor(idx: ImGuiCol_FrameBgActive, col: (ImVec4)ImColor::HSV(h: i / 7.0f, s: 0.7f, v: 0.5f));
2375 ImGui::PushStyleColor(idx: ImGuiCol_SliderGrab, col: (ImVec4)ImColor::HSV(h: i / 7.0f, s: 0.9f, v: 0.9f));
2376 ImGui::VSliderFloat(label: "##v", size: ImVec2(18, 160), v: &values[i], v_min: 0.0f, v_max: 1.0f, format: "");
2377 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2378 ImGui::SetTooltip("%.3f", values[i]);
2379 ImGui::PopStyleColor(count: 4);
2380 ImGui::PopID();
2381 }
2382 ImGui::PopID();
2383
2384 ImGui::SameLine();
2385 ImGui::PushID(str_id: "set2");
2386 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
2387 const int rows = 3;
2388 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
2389 for (int nx = 0; nx < 4; nx++)
2390 {
2391 if (nx > 0) ImGui::SameLine();
2392 ImGui::BeginGroup();
2393 for (int ny = 0; ny < rows; ny++)
2394 {
2395 ImGui::PushID(int_id: nx * rows + ny);
2396 ImGui::VSliderFloat(label: "##v", size: small_slider_size, v: &values2[nx], v_min: 0.0f, v_max: 1.0f, format: "");
2397 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2398 ImGui::SetTooltip("%.3f", values2[nx]);
2399 ImGui::PopID();
2400 }
2401 ImGui::EndGroup();
2402 }
2403 ImGui::PopID();
2404
2405 ImGui::SameLine();
2406 ImGui::PushID(str_id: "set3");
2407 for (int i = 0; i < 4; i++)
2408 {
2409 if (i > 0) ImGui::SameLine();
2410 ImGui::PushID(int_id: i);
2411 ImGui::PushStyleVar(idx: ImGuiStyleVar_GrabMinSize, val: 40);
2412 ImGui::VSliderFloat(label: "##v", size: ImVec2(40, 160), v: &values[i], v_min: 0.0f, v_max: 1.0f, format: "%.2f\nsec");
2413 ImGui::PopStyleVar();
2414 ImGui::PopID();
2415 }
2416 ImGui::PopID();
2417 ImGui::PopStyleVar();
2418 ImGui::TreePop();
2419 }
2420
2421 IMGUI_DEMO_MARKER("Widgets/Drag and drop");
2422 if (ImGui::TreeNode(label: "Drag and Drop"))
2423 {
2424 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
2425 if (ImGui::TreeNode(label: "Drag and drop in standard widgets"))
2426 {
2427 // ColorEdit widgets automatically act as drag source and drag target.
2428 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
2429 // to allow your own widgets to use colors in their drag and drop interaction.
2430 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
2431 HelpMarker(desc: "You can drag from the color squares.");
2432 static float col1[3] = { 1.0f, 0.0f, 0.2f };
2433 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
2434 ImGui::ColorEdit3(label: "color 1", col: col1);
2435 ImGui::ColorEdit4(label: "color 2", col: col2);
2436 ImGui::TreePop();
2437 }
2438
2439 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
2440 if (ImGui::TreeNode(label: "Drag and drop to copy/swap items"))
2441 {
2442 enum Mode
2443 {
2444 Mode_Copy,
2445 Mode_Move,
2446 Mode_Swap
2447 };
2448 static int mode = 0;
2449 if (ImGui::RadioButton(label: "Copy", active: mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
2450 if (ImGui::RadioButton(label: "Move", active: mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
2451 if (ImGui::RadioButton(label: "Swap", active: mode == Mode_Swap)) { mode = Mode_Swap; }
2452 static const char* names[9] =
2453 {
2454 "Bobby", "Beatrice", "Betty",
2455 "Brianna", "Barry", "Bernard",
2456 "Bibi", "Blaine", "Bryn"
2457 };
2458 for (int n = 0; n < IM_ARRAYSIZE(names); n++)
2459 {
2460 ImGui::PushID(int_id: n);
2461 if ((n % 3) != 0)
2462 ImGui::SameLine();
2463 ImGui::Button(label: names[n], size: ImVec2(60, 60));
2464
2465 // Our buttons are both drag sources and drag targets here!
2466 if (ImGui::BeginDragDropSource(flags: ImGuiDragDropFlags_None))
2467 {
2468 // Set payload to carry the index of our item (could be anything)
2469 ImGui::SetDragDropPayload(type: "DND_DEMO_CELL", data: &n, sz: sizeof(int));
2470
2471 // Display preview (could be anything, e.g. when dragging an image we could decide to display
2472 // the filename and a small preview of the image, etc.)
2473 if (mode == Mode_Copy) { ImGui::Text(fmt: "Copy %s", names[n]); }
2474 if (mode == Mode_Move) { ImGui::Text(fmt: "Move %s", names[n]); }
2475 if (mode == Mode_Swap) { ImGui::Text(fmt: "Swap %s", names[n]); }
2476 ImGui::EndDragDropSource();
2477 }
2478 if (ImGui::BeginDragDropTarget())
2479 {
2480 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(type: "DND_DEMO_CELL"))
2481 {
2482 IM_ASSERT(payload->DataSize == sizeof(int));
2483 int payload_n = *(const int*)payload->Data;
2484 if (mode == Mode_Copy)
2485 {
2486 names[n] = names[payload_n];
2487 }
2488 if (mode == Mode_Move)
2489 {
2490 names[n] = names[payload_n];
2491 names[payload_n] = "";
2492 }
2493 if (mode == Mode_Swap)
2494 {
2495 const char* tmp = names[n];
2496 names[n] = names[payload_n];
2497 names[payload_n] = tmp;
2498 }
2499 }
2500 ImGui::EndDragDropTarget();
2501 }
2502 ImGui::PopID();
2503 }
2504 ImGui::TreePop();
2505 }
2506
2507 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
2508 if (ImGui::TreeNode(label: "Drag to reorder items (simple)"))
2509 {
2510 // Simple reordering
2511 HelpMarker(
2512 desc: "We don't use the drag and drop api at all here! "
2513 "Instead we query when the item is held but not hovered, and order items accordingly.");
2514 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
2515 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
2516 {
2517 const char* item = item_names[n];
2518 ImGui::Selectable(label: item);
2519
2520 if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
2521 {
2522 int n_next = n + (ImGui::GetMouseDragDelta(button: 0).y < 0.f ? -1 : 1);
2523 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
2524 {
2525 item_names[n] = item_names[n_next];
2526 item_names[n_next] = item;
2527 ImGui::ResetMouseDragDelta();
2528 }
2529 }
2530 }
2531 ImGui::TreePop();
2532 }
2533
2534 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
2535 if (ImGui::TreeNode(label: "Tooltip at target location"))
2536 {
2537 for (int n = 0; n < 2; n++)
2538 {
2539 // Drop targets
2540 ImGui::Button(label: n ? "drop here##1" : "drop here##0");
2541 if (ImGui::BeginDragDropTarget())
2542 {
2543 ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
2544 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, flags: drop_target_flags))
2545 {
2546 IM_UNUSED(payload);
2547 ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
2548 ImGui::SetTooltip("Cannot drop here!");
2549 }
2550 ImGui::EndDragDropTarget();
2551 }
2552
2553 // Drop source
2554 static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
2555 if (n == 0)
2556 ImGui::ColorButton(desc_id: "drag me", col: col4);
2557
2558 }
2559 ImGui::TreePop();
2560 }
2561
2562 ImGui::TreePop();
2563 }
2564
2565 IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2566 if (ImGui::TreeNode(label: "Querying Item Status (Edited/Active/Hovered etc.)"))
2567 {
2568 // Select an item type
2569 const char* item_names[] =
2570 {
2571 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2572 "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2573 };
2574 static int item_type = 4;
2575 static bool item_disabled = false;
2576 ImGui::Combo(label: "Item Type", current_item: &item_type, items: item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
2577 ImGui::SameLine();
2578 HelpMarker(desc: "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().");
2579 ImGui::Checkbox(label: "Item Disabled", v: &item_disabled);
2580
2581 // Submit selected items so we can query their status in the code following it.
2582 bool ret = false;
2583 static bool b = false;
2584 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2585 static char str[16] = {};
2586 if (item_disabled)
2587 ImGui::BeginDisabled(disabled: true);
2588 if (item_type == 0) { ImGui::Text(fmt: "ITEM: Text"); } // Testing text items with no identifier/interaction
2589 if (item_type == 1) { ret = ImGui::Button(label: "ITEM: Button"); } // Testing button
2590 if (item_type == 2) { ImGui::PushButtonRepeat(repeat: true); ret = ImGui::Button(label: "ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
2591 if (item_type == 3) { ret = ImGui::Checkbox(label: "ITEM: Checkbox", v: &b); } // Testing checkbox
2592 if (item_type == 4) { ret = ImGui::SliderFloat(label: "ITEM: SliderFloat", v: &col4f[0], v_min: 0.0f, v_max: 1.0f); } // Testing basic item
2593 if (item_type == 5) { ret = ImGui::InputText(label: "ITEM: InputText", buf: &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
2594 if (item_type == 6) { ret = ImGui::InputTextMultiline(label: "ITEM: InputTextMultiline", buf: &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window)
2595 if (item_type == 7) { ret = ImGui::InputFloat(label: "ITEM: InputFloat", v: col4f, step: 1.0f); } // Testing +/- buttons on scalar input
2596 if (item_type == 8) { ret = ImGui::InputFloat3(label: "ITEM: InputFloat3", v: col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2597 if (item_type == 9) { ret = ImGui::ColorEdit4(label: "ITEM: ColorEdit4", col: col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2598 if (item_type == 10){ ret = ImGui::Selectable(label: "ITEM: Selectable"); } // Testing selectable item
2599 if (item_type == 11){ ret = ImGui::MenuItem(label: "ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2600 if (item_type == 12){ ret = ImGui::TreeNode(label: "ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
2601 if (item_type == 13){ ret = ImGui::TreeNodeEx(label: "ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", flags: ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2602 if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo(label: "ITEM: Combo", current_item: &current, items, IM_ARRAYSIZE(items)); }
2603 if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox(label: "ITEM: ListBox", current_item: &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
2604
2605 bool hovered_delay_none = ImGui::IsItemHovered();
2606 bool hovered_delay_stationary = ImGui::IsItemHovered(flags: ImGuiHoveredFlags_Stationary);
2607 bool hovered_delay_short = ImGui::IsItemHovered(flags: ImGuiHoveredFlags_DelayShort);
2608 bool hovered_delay_normal = ImGui::IsItemHovered(flags: ImGuiHoveredFlags_DelayNormal);
2609 bool hovered_delay_tooltip = ImGui::IsItemHovered(flags: ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2610
2611 // Display the values of IsItemHovered() and other common item state functions.
2612 // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2613 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2614 // we query every state in a single call to avoid storing them and to simplify the code.
2615 ImGui::BulletText(
2616 fmt: "Return value = %d\n"
2617 "IsItemFocused() = %d\n"
2618 "IsItemHovered() = %d\n"
2619 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2620 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2621 "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2622 "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2623 "IsItemHovered(_AllowWhenDisabled) = %d\n"
2624 "IsItemHovered(_RectOnly) = %d\n"
2625 "IsItemActive() = %d\n"
2626 "IsItemEdited() = %d\n"
2627 "IsItemActivated() = %d\n"
2628 "IsItemDeactivated() = %d\n"
2629 "IsItemDeactivatedAfterEdit() = %d\n"
2630 "IsItemVisible() = %d\n"
2631 "IsItemClicked() = %d\n"
2632 "IsItemToggledOpen() = %d\n"
2633 "GetItemRectMin() = (%.1f, %.1f)\n"
2634 "GetItemRectMax() = (%.1f, %.1f)\n"
2635 "GetItemRectSize() = (%.1f, %.1f)",
2636 ret,
2637 ImGui::IsItemFocused(),
2638 ImGui::IsItemHovered(),
2639 ImGui::IsItemHovered(flags: ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2640 ImGui::IsItemHovered(flags: ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2641 ImGui::IsItemHovered(flags: ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2642 ImGui::IsItemHovered(flags: ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2643 ImGui::IsItemHovered(flags: ImGuiHoveredFlags_AllowWhenDisabled),
2644 ImGui::IsItemHovered(flags: ImGuiHoveredFlags_RectOnly),
2645 ImGui::IsItemActive(),
2646 ImGui::IsItemEdited(),
2647 ImGui::IsItemActivated(),
2648 ImGui::IsItemDeactivated(),
2649 ImGui::IsItemDeactivatedAfterEdit(),
2650 ImGui::IsItemVisible(),
2651 ImGui::IsItemClicked(),
2652 ImGui::IsItemToggledOpen(),
2653 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2654 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2655 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2656 );
2657 ImGui::BulletText(
2658 fmt: "with Hovering Delay or Stationary test:\n"
2659 "IsItemHovered() = = %d\n"
2660 "IsItemHovered(_Stationary) = %d\n"
2661 "IsItemHovered(_DelayShort) = %d\n"
2662 "IsItemHovered(_DelayNormal) = %d\n"
2663 "IsItemHovered(_Tooltip) = %d",
2664 hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2665
2666 if (item_disabled)
2667 ImGui::EndDisabled();
2668
2669 char buf[1] = "";
2670 ImGui::InputText(label: "unused", buf, IM_ARRAYSIZE(buf), flags: ImGuiInputTextFlags_ReadOnly);
2671 ImGui::SameLine();
2672 HelpMarker(desc: "This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2673
2674 ImGui::TreePop();
2675 }
2676
2677 IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2678 if (ImGui::TreeNode(label: "Querying Window Status (Focused/Hovered etc.)"))
2679 {
2680 static bool embed_all_inside_a_child_window = false;
2681 ImGui::Checkbox(label: "Embed everything inside a child window for testing _RootWindow flag.", v: &embed_all_inside_a_child_window);
2682 if (embed_all_inside_a_child_window)
2683 ImGui::BeginChild(str_id: "outer_child", size: ImVec2(0, ImGui::GetFontSize() * 20.0f), child_flags: ImGuiChildFlags_Border);
2684
2685 // Testing IsWindowFocused() function with its various flags.
2686 ImGui::BulletText(
2687 fmt: "IsWindowFocused() = %d\n"
2688 "IsWindowFocused(_ChildWindows) = %d\n"
2689 "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2690 "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
2691 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2692 "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2693 "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2694 "IsWindowFocused(_RootWindow) = %d\n"
2695 "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2696 "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
2697 "IsWindowFocused(_AnyWindow) = %d\n",
2698 ImGui::IsWindowFocused(),
2699 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_ChildWindows),
2700 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2701 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
2702 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2703 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2704 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2705 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_RootWindow),
2706 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2707 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2708 ImGui::IsWindowFocused(flags: ImGuiFocusedFlags_AnyWindow));
2709
2710 // Testing IsWindowHovered() function with its various flags.
2711 ImGui::BulletText(
2712 fmt: "IsWindowHovered() = %d\n"
2713 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2714 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2715 "IsWindowHovered(_ChildWindows) = %d\n"
2716 "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2717 "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
2718 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2719 "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2720 "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2721 "IsWindowHovered(_RootWindow) = %d\n"
2722 "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2723 "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
2724 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2725 "IsWindowHovered(_AnyWindow) = %d\n"
2726 "IsWindowHovered(_Stationary) = %d\n",
2727 ImGui::IsWindowHovered(),
2728 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2729 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2730 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_ChildWindows),
2731 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2732 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
2733 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2734 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2735 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2736 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_RootWindow),
2737 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2738 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2739 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2740 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_AnyWindow),
2741 ImGui::IsWindowHovered(flags: ImGuiHoveredFlags_Stationary));
2742
2743 ImGui::BeginChild(str_id: "child", size: ImVec2(0, 50), child_flags: ImGuiChildFlags_Border);
2744 ImGui::Text(fmt: "This is another child window for testing the _ChildWindows flag.");
2745 ImGui::EndChild();
2746 if (embed_all_inside_a_child_window)
2747 ImGui::EndChild();
2748
2749 // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2750 // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2751 // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2752 static bool test_window = false;
2753 ImGui::Checkbox(label: "Hovered/Active tests after Begin() for title bar testing", v: &test_window);
2754 if (test_window)
2755 {
2756 // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2757 // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2758 ImGui::Begin(name: "Title bar Hovered/Active tests", p_open: &test_window);
2759 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2760 {
2761 if (ImGui::MenuItem(label: "Close")) { test_window = false; }
2762 ImGui::EndPopup();
2763 }
2764 ImGui::Text(
2765 fmt: "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2766 "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2767 ImGui::IsItemHovered(), ImGui::IsItemActive());
2768 ImGui::End();
2769 }
2770
2771 ImGui::TreePop();
2772 }
2773
2774 // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd:
2775 // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space)
2776 if (disable_all)
2777 ImGui::EndDisabled();
2778
2779 IMGUI_DEMO_MARKER("Widgets/Disable Block");
2780 if (ImGui::TreeNode(label: "Disable block"))
2781 {
2782 ImGui::Checkbox(label: "Disable entire section above", v: &disable_all);
2783 ImGui::SameLine(); HelpMarker(desc: "Demonstrate using BeginDisabled()/EndDisabled() across this section.");
2784 ImGui::TreePop();
2785 }
2786
2787 IMGUI_DEMO_MARKER("Widgets/Text Filter");
2788 if (ImGui::TreeNode(label: "Text Filter"))
2789 {
2790 // Helper class to easy setup a text filter.
2791 // You may want to implement a more feature-full filtering scheme in your own application.
2792 HelpMarker(desc: "Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
2793 static ImGuiTextFilter filter;
2794 ImGui::Text(fmt: "Filter usage:\n"
2795 " \"\" display all lines\n"
2796 " \"xxx\" display lines containing \"xxx\"\n"
2797 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
2798 " \"-xxx\" hide lines containing \"xxx\"");
2799 filter.Draw();
2800 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
2801 for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
2802 if (filter.PassFilter(text: lines[i]))
2803 ImGui::BulletText(fmt: "%s", lines[i]);
2804 ImGui::TreePop();
2805 }
2806}
2807
2808static void ShowDemoWindowLayout()
2809{
2810 IMGUI_DEMO_MARKER("Layout");
2811 if (!ImGui::CollapsingHeader(label: "Layout & Scrolling"))
2812 return;
2813
2814 IMGUI_DEMO_MARKER("Layout/Child windows");
2815 if (ImGui::TreeNode(label: "Child windows"))
2816 {
2817 ImGui::SeparatorText(label: "Child windows");
2818
2819 HelpMarker(desc: "Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
2820 static bool disable_mouse_wheel = false;
2821 static bool disable_menu = false;
2822 ImGui::Checkbox(label: "Disable Mouse Wheel", v: &disable_mouse_wheel);
2823 ImGui::Checkbox(label: "Disable Menu", v: &disable_menu);
2824
2825 // Child 1: no border, enable horizontal scrollbar
2826 {
2827 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
2828 if (disable_mouse_wheel)
2829 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2830 ImGui::BeginChild(str_id: "ChildL", size: ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), child_flags: ImGuiChildFlags_None, window_flags);
2831 for (int i = 0; i < 100; i++)
2832 ImGui::Text(fmt: "%04d: scrollable region", i);
2833 ImGui::EndChild();
2834 }
2835
2836 ImGui::SameLine();
2837
2838 // Child 2: rounded border
2839 {
2840 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
2841 if (disable_mouse_wheel)
2842 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2843 if (!disable_menu)
2844 window_flags |= ImGuiWindowFlags_MenuBar;
2845 ImGui::PushStyleVar(idx: ImGuiStyleVar_ChildRounding, val: 5.0f);
2846 ImGui::BeginChild(str_id: "ChildR", size: ImVec2(0, 260), child_flags: ImGuiChildFlags_Border, window_flags);
2847 if (!disable_menu && ImGui::BeginMenuBar())
2848 {
2849 if (ImGui::BeginMenu(label: "Menu"))
2850 {
2851 ShowExampleMenuFile();
2852 ImGui::EndMenu();
2853 }
2854 ImGui::EndMenuBar();
2855 }
2856 if (ImGui::BeginTable(str_id: "split", column: 2, flags: ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
2857 {
2858 for (int i = 0; i < 100; i++)
2859 {
2860 char buf[32];
2861 sprintf(s: buf, format: "%03d", i);
2862 ImGui::TableNextColumn();
2863 ImGui::Button(label: buf, size: ImVec2(-FLT_MIN, 0.0f));
2864 }
2865 ImGui::EndTable();
2866 }
2867 ImGui::EndChild();
2868 ImGui::PopStyleVar();
2869 }
2870
2871 // Child 3: manual-resize
2872 ImGui::SeparatorText(label: "Manual-resize");
2873 {
2874 HelpMarker(desc: "Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
2875 ImGui::PushStyleColor(idx: ImGuiCol_ChildBg, col: ImGui::GetStyleColorVec4(idx: ImGuiCol_FrameBg));
2876 if (ImGui::BeginChild(str_id: "ResizableChild", size: ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), child_flags: ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY))
2877 for (int n = 0; n < 10; n++)
2878 ImGui::Text(fmt: "Line %04d", n);
2879 ImGui::PopStyleColor();
2880 ImGui::EndChild();
2881 }
2882
2883 // Child 4: auto-resizing height with a limit
2884 ImGui::SeparatorText(label: "Auto-resize with constraints");
2885 {
2886 static int draw_lines = 3;
2887 static int max_height_in_lines = 10;
2888 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2889 ImGui::DragInt(label: "Lines Count", v: &draw_lines, v_speed: 0.2f);
2890 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2891 ImGui::DragInt(label: "Max Height (in Lines)", v: &max_height_in_lines, v_speed: 0.2f);
2892
2893 ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), size_max: ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
2894 if (ImGui::BeginChild(str_id: "ConstrainedChild", size: ImVec2(-FLT_MIN, 0.0f), child_flags: ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY))
2895 for (int n = 0; n < draw_lines; n++)
2896 ImGui::Text(fmt: "Line %04d", n);
2897 ImGui::EndChild();
2898 }
2899
2900 ImGui::SeparatorText(label: "Misc/Advanced");
2901
2902 // Demonstrate a few extra things
2903 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
2904 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
2905 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively
2906 // layout from this position.
2907 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
2908 // the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
2909 {
2910 static int offset_x = 0;
2911 static bool override_bg_color = true;
2912 static ImGuiChildFlags child_flags = ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
2913 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2914 ImGui::DragInt(label: "Offset X", v: &offset_x, v_speed: 1.0f, v_min: -1000, v_max: 1000);
2915 ImGui::Checkbox(label: "Override ChildBg color", v: &override_bg_color);
2916 ImGui::CheckboxFlags(label: "ImGuiChildFlags_Border", flags: &child_flags, flags_value: ImGuiChildFlags_Border);
2917 ImGui::CheckboxFlags(label: "ImGuiChildFlags_AlwaysUseWindowPadding", flags: &child_flags, flags_value: ImGuiChildFlags_AlwaysUseWindowPadding);
2918 ImGui::CheckboxFlags(label: "ImGuiChildFlags_ResizeX", flags: &child_flags, flags_value: ImGuiChildFlags_ResizeX);
2919 ImGui::CheckboxFlags(label: "ImGuiChildFlags_ResizeY", flags: &child_flags, flags_value: ImGuiChildFlags_ResizeY);
2920 ImGui::CheckboxFlags(label: "ImGuiChildFlags_FrameStyle", flags: &child_flags, flags_value: ImGuiChildFlags_FrameStyle);
2921 ImGui::SameLine(); HelpMarker(desc: "Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
2922 if (child_flags & ImGuiChildFlags_FrameStyle)
2923 override_bg_color = false;
2924
2925 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
2926 if (override_bg_color)
2927 ImGui::PushStyleColor(idx: ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
2928 ImGui::BeginChild(str_id: "Red", size: ImVec2(200, 100), child_flags, window_flags: ImGuiWindowFlags_None);
2929 if (override_bg_color)
2930 ImGui::PopStyleColor();
2931
2932 for (int n = 0; n < 50; n++)
2933 ImGui::Text(fmt: "Some test %d", n);
2934 ImGui::EndChild();
2935 bool child_is_hovered = ImGui::IsItemHovered();
2936 ImVec2 child_rect_min = ImGui::GetItemRectMin();
2937 ImVec2 child_rect_max = ImGui::GetItemRectMax();
2938 ImGui::Text(fmt: "Hovered: %d", child_is_hovered);
2939 ImGui::Text(fmt: "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);
2940 }
2941
2942 ImGui::TreePop();
2943 }
2944
2945 IMGUI_DEMO_MARKER("Layout/Widgets Width");
2946 if (ImGui::TreeNode(label: "Widgets Width"))
2947 {
2948 static float f = 0.0f;
2949 static bool show_indented_items = true;
2950 ImGui::Checkbox(label: "Show indented items", v: &show_indented_items);
2951
2952 // Use SetNextItemWidth() to set the width of a single upcoming item.
2953 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
2954 // In real code use you'll probably want to choose width values that are proportional to your font size
2955 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
2956
2957 ImGui::Text(fmt: "SetNextItemWidth/PushItemWidth(100)");
2958 ImGui::SameLine(); HelpMarker(desc: "Fixed width.");
2959 ImGui::PushItemWidth(item_width: 100);
2960 ImGui::DragFloat(label: "float##1b", v: &f);
2961 if (show_indented_items)
2962 {
2963 ImGui::Indent();
2964 ImGui::DragFloat(label: "float (indented)##1b", v: &f);
2965 ImGui::Unindent();
2966 }
2967 ImGui::PopItemWidth();
2968
2969 ImGui::Text(fmt: "SetNextItemWidth/PushItemWidth(-100)");
2970 ImGui::SameLine(); HelpMarker(desc: "Align to right edge minus 100");
2971 ImGui::PushItemWidth(item_width: -100);
2972 ImGui::DragFloat(label: "float##2a", v: &f);
2973 if (show_indented_items)
2974 {
2975 ImGui::Indent();
2976 ImGui::DragFloat(label: "float (indented)##2b", v: &f);
2977 ImGui::Unindent();
2978 }
2979 ImGui::PopItemWidth();
2980
2981 ImGui::Text(fmt: "SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
2982 ImGui::SameLine(); HelpMarker(desc: "Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
2983 ImGui::PushItemWidth(item_width: ImGui::GetContentRegionAvail().x * 0.5f);
2984 ImGui::DragFloat(label: "float##3a", v: &f);
2985 if (show_indented_items)
2986 {
2987 ImGui::Indent();
2988 ImGui::DragFloat(label: "float (indented)##3b", v: &f);
2989 ImGui::Unindent();
2990 }
2991 ImGui::PopItemWidth();
2992
2993 ImGui::Text(fmt: "SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
2994 ImGui::SameLine(); HelpMarker(desc: "Align to right edge minus half");
2995 ImGui::PushItemWidth(item_width: -ImGui::GetContentRegionAvail().x * 0.5f);
2996 ImGui::DragFloat(label: "float##4a", v: &f);
2997 if (show_indented_items)
2998 {
2999 ImGui::Indent();
3000 ImGui::DragFloat(label: "float (indented)##4b", v: &f);
3001 ImGui::Unindent();
3002 }
3003 ImGui::PopItemWidth();
3004
3005 // Demonstrate using PushItemWidth to surround three items.
3006 // Calling SetNextItemWidth() before each of them would have the same effect.
3007 ImGui::Text(fmt: "SetNextItemWidth/PushItemWidth(-FLT_MIN)");
3008 ImGui::SameLine(); HelpMarker(desc: "Align to right edge");
3009 ImGui::PushItemWidth(item_width: -FLT_MIN);
3010 ImGui::DragFloat(label: "##float5a", v: &f);
3011 if (show_indented_items)
3012 {
3013 ImGui::Indent();
3014 ImGui::DragFloat(label: "float (indented)##5b", v: &f);
3015 ImGui::Unindent();
3016 }
3017 ImGui::PopItemWidth();
3018
3019 ImGui::TreePop();
3020 }
3021
3022 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
3023 if (ImGui::TreeNode(label: "Basic Horizontal Layout"))
3024 {
3025 ImGui::TextWrapped(fmt: "(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
3026
3027 // Text
3028 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
3029 ImGui::Text(fmt: "Two items: Hello"); ImGui::SameLine();
3030 ImGui::TextColored(col: ImVec4(1, 1, 0, 1), fmt: "Sailor");
3031
3032 // Adjust spacing
3033 ImGui::Text(fmt: "More spacing: Hello"); ImGui::SameLine(offset_from_start_x: 0, spacing: 20);
3034 ImGui::TextColored(col: ImVec4(1, 1, 0, 1), fmt: "Sailor");
3035
3036 // Button
3037 ImGui::AlignTextToFramePadding();
3038 ImGui::Text(fmt: "Normal buttons"); ImGui::SameLine();
3039 ImGui::Button(label: "Banana"); ImGui::SameLine();
3040 ImGui::Button(label: "Apple"); ImGui::SameLine();
3041 ImGui::Button(label: "Corniflower");
3042
3043 // Button
3044 ImGui::Text(fmt: "Small buttons"); ImGui::SameLine();
3045 ImGui::SmallButton(label: "Like this one"); ImGui::SameLine();
3046 ImGui::Text(fmt: "can fit within a text block.");
3047
3048 // Aligned to arbitrary position. Easy/cheap column.
3049 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
3050 ImGui::Text(fmt: "Aligned");
3051 ImGui::SameLine(offset_from_start_x: 150); ImGui::Text(fmt: "x=150");
3052 ImGui::SameLine(offset_from_start_x: 300); ImGui::Text(fmt: "x=300");
3053 ImGui::Text(fmt: "Aligned");
3054 ImGui::SameLine(offset_from_start_x: 150); ImGui::SmallButton(label: "x=150");
3055 ImGui::SameLine(offset_from_start_x: 300); ImGui::SmallButton(label: "x=300");
3056
3057 // Checkbox
3058 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
3059 static bool c1 = false, c2 = false, c3 = false, c4 = false;
3060 ImGui::Checkbox(label: "My", v: &c1); ImGui::SameLine();
3061 ImGui::Checkbox(label: "Tailor", v: &c2); ImGui::SameLine();
3062 ImGui::Checkbox(label: "Is", v: &c3); ImGui::SameLine();
3063 ImGui::Checkbox(label: "Rich", v: &c4);
3064
3065 // Various
3066 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
3067 ImGui::PushItemWidth(item_width: 80);
3068 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
3069 static int item = -1;
3070 ImGui::Combo(label: "Combo", current_item: &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
3071 ImGui::SliderFloat(label: "X", v: &f0, v_min: 0.0f, v_max: 5.0f); ImGui::SameLine();
3072 ImGui::SliderFloat(label: "Y", v: &f1, v_min: 0.0f, v_max: 5.0f); ImGui::SameLine();
3073 ImGui::SliderFloat(label: "Z", v: &f2, v_min: 0.0f, v_max: 5.0f);
3074 ImGui::PopItemWidth();
3075
3076 ImGui::PushItemWidth(item_width: 80);
3077 ImGui::Text(fmt: "Lists:");
3078 static int selection[4] = { 0, 1, 2, 3 };
3079 for (int i = 0; i < 4; i++)
3080 {
3081 if (i > 0) ImGui::SameLine();
3082 ImGui::PushID(int_id: i);
3083 ImGui::ListBox(label: "", current_item: &selection[i], items, IM_ARRAYSIZE(items));
3084 ImGui::PopID();
3085 //ImGui::SetItemTooltip("ListBox %d hovered", i);
3086 }
3087 ImGui::PopItemWidth();
3088
3089 // Dummy
3090 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
3091 ImVec2 button_sz(40, 40);
3092 ImGui::Button(label: "A", size: button_sz); ImGui::SameLine();
3093 ImGui::Dummy(size: button_sz); ImGui::SameLine();
3094 ImGui::Button(label: "B", size: button_sz);
3095
3096 // Manually wrapping
3097 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
3098 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
3099 ImGui::Text(fmt: "Manual wrapping:");
3100 ImGuiStyle& style = ImGui::GetStyle();
3101 int buttons_count = 20;
3102 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
3103 for (int n = 0; n < buttons_count; n++)
3104 {
3105 ImGui::PushID(int_id: n);
3106 ImGui::Button(label: "Box", size: button_sz);
3107 float last_button_x2 = ImGui::GetItemRectMax().x;
3108 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
3109 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
3110 ImGui::SameLine();
3111 ImGui::PopID();
3112 }
3113
3114 ImGui::TreePop();
3115 }
3116
3117 IMGUI_DEMO_MARKER("Layout/Groups");
3118 if (ImGui::TreeNode(label: "Groups"))
3119 {
3120 HelpMarker(
3121 desc: "BeginGroup() basically locks the horizontal position for new line. "
3122 "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
3123 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
3124 ImGui::BeginGroup();
3125 {
3126 ImGui::BeginGroup();
3127 ImGui::Button(label: "AAA");
3128 ImGui::SameLine();
3129 ImGui::Button(label: "BBB");
3130 ImGui::SameLine();
3131 ImGui::BeginGroup();
3132 ImGui::Button(label: "CCC");
3133 ImGui::Button(label: "DDD");
3134 ImGui::EndGroup();
3135 ImGui::SameLine();
3136 ImGui::Button(label: "EEE");
3137 ImGui::EndGroup();
3138 ImGui::SetItemTooltip("First group hovered");
3139 }
3140 // Capture the group size and create widgets using the same size
3141 ImVec2 size = ImGui::GetItemRectSize();
3142 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
3143 ImGui::PlotHistogram(label: "##values", values, IM_ARRAYSIZE(values), values_offset: 0, NULL, scale_min: 0.0f, scale_max: 1.0f, graph_size: size);
3144
3145 ImGui::Button(label: "ACTION", size: ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
3146 ImGui::SameLine();
3147 ImGui::Button(label: "REACTION", size: ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
3148 ImGui::EndGroup();
3149 ImGui::SameLine();
3150
3151 ImGui::Button(label: "LEVERAGE\nBUZZWORD", size);
3152 ImGui::SameLine();
3153
3154 if (ImGui::BeginListBox(label: "List", size))
3155 {
3156 ImGui::Selectable(label: "Selected", selected: true);
3157 ImGui::Selectable(label: "Not Selected", selected: false);
3158 ImGui::EndListBox();
3159 }
3160
3161 ImGui::TreePop();
3162 }
3163
3164 IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
3165 if (ImGui::TreeNode(label: "Text Baseline Alignment"))
3166 {
3167 {
3168 ImGui::BulletText(fmt: "Text baseline:");
3169 ImGui::SameLine(); HelpMarker(
3170 desc: "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
3171 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
3172 ImGui::Indent();
3173
3174 ImGui::Text(fmt: "KO Blahblah"); ImGui::SameLine();
3175 ImGui::Button(label: "Some framed item"); ImGui::SameLine();
3176 HelpMarker(desc: "Baseline of button will look misaligned with text..");
3177
3178 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
3179 // (because we don't know what's coming after the Text() statement, we need to move the text baseline
3180 // down by FramePadding.y ahead of time)
3181 ImGui::AlignTextToFramePadding();
3182 ImGui::Text(fmt: "OK Blahblah"); ImGui::SameLine();
3183 ImGui::Button(label: "Some framed item"); ImGui::SameLine();
3184 HelpMarker(desc: "We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
3185
3186 // SmallButton() uses the same vertical padding as Text
3187 ImGui::Button(label: "TEST##1"); ImGui::SameLine();
3188 ImGui::Text(fmt: "TEST"); ImGui::SameLine();
3189 ImGui::SmallButton(label: "TEST##2");
3190
3191 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
3192 ImGui::AlignTextToFramePadding();
3193 ImGui::Text(fmt: "Text aligned to framed item"); ImGui::SameLine();
3194 ImGui::Button(label: "Item##1"); ImGui::SameLine();
3195 ImGui::Text(fmt: "Item"); ImGui::SameLine();
3196 ImGui::SmallButton(label: "Item##2"); ImGui::SameLine();
3197 ImGui::Button(label: "Item##3");
3198
3199 ImGui::Unindent();
3200 }
3201
3202 ImGui::Spacing();
3203
3204 {
3205 ImGui::BulletText(fmt: "Multi-line text:");
3206 ImGui::Indent();
3207 ImGui::Text(fmt: "One\nTwo\nThree"); ImGui::SameLine();
3208 ImGui::Text(fmt: "Hello\nWorld"); ImGui::SameLine();
3209 ImGui::Text(fmt: "Banana");
3210
3211 ImGui::Text(fmt: "Banana"); ImGui::SameLine();
3212 ImGui::Text(fmt: "Hello\nWorld"); ImGui::SameLine();
3213 ImGui::Text(fmt: "One\nTwo\nThree");
3214
3215 ImGui::Button(label: "HOP##1"); ImGui::SameLine();
3216 ImGui::Text(fmt: "Banana"); ImGui::SameLine();
3217 ImGui::Text(fmt: "Hello\nWorld"); ImGui::SameLine();
3218 ImGui::Text(fmt: "Banana");
3219
3220 ImGui::Button(label: "HOP##2"); ImGui::SameLine();
3221 ImGui::Text(fmt: "Hello\nWorld"); ImGui::SameLine();
3222 ImGui::Text(fmt: "Banana");
3223 ImGui::Unindent();
3224 }
3225
3226 ImGui::Spacing();
3227
3228 {
3229 ImGui::BulletText(fmt: "Misc items:");
3230 ImGui::Indent();
3231
3232 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
3233 ImGui::Button(label: "80x80", size: ImVec2(80, 80));
3234 ImGui::SameLine();
3235 ImGui::Button(label: "50x50", size: ImVec2(50, 50));
3236 ImGui::SameLine();
3237 ImGui::Button(label: "Button()");
3238 ImGui::SameLine();
3239 ImGui::SmallButton(label: "SmallButton()");
3240
3241 // Tree
3242 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
3243 ImGui::Button(label: "Button##1");
3244 ImGui::SameLine(offset_from_start_x: 0.0f, spacing);
3245 if (ImGui::TreeNode(label: "Node##1"))
3246 {
3247 // Placeholder tree data
3248 for (int i = 0; i < 6; i++)
3249 ImGui::BulletText(fmt: "Item %d..", i);
3250 ImGui::TreePop();
3251 }
3252
3253 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
3254 // Otherwise you can use SmallButton() (smaller fit).
3255 ImGui::AlignTextToFramePadding();
3256
3257 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
3258 // other contents below the node.
3259 bool node_open = ImGui::TreeNode(label: "Node##2");
3260 ImGui::SameLine(offset_from_start_x: 0.0f, spacing); ImGui::Button(label: "Button##2");
3261 if (node_open)
3262 {
3263 // Placeholder tree data
3264 for (int i = 0; i < 6; i++)
3265 ImGui::BulletText(fmt: "Item %d..", i);
3266 ImGui::TreePop();
3267 }
3268
3269 // Bullet
3270 ImGui::Button(label: "Button##3");
3271 ImGui::SameLine(offset_from_start_x: 0.0f, spacing);
3272 ImGui::BulletText(fmt: "Bullet text");
3273
3274 ImGui::AlignTextToFramePadding();
3275 ImGui::BulletText(fmt: "Node");
3276 ImGui::SameLine(offset_from_start_x: 0.0f, spacing); ImGui::Button(label: "Button##4");
3277 ImGui::Unindent();
3278 }
3279
3280 ImGui::TreePop();
3281 }
3282
3283 IMGUI_DEMO_MARKER("Layout/Scrolling");
3284 if (ImGui::TreeNode(label: "Scrolling"))
3285 {
3286 // Vertical scroll functions
3287 IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
3288 HelpMarker(desc: "Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
3289
3290 static int track_item = 50;
3291 static bool enable_track = true;
3292 static bool enable_extra_decorations = false;
3293 static float scroll_to_off_px = 0.0f;
3294 static float scroll_to_pos_px = 200.0f;
3295
3296 ImGui::Checkbox(label: "Decoration", v: &enable_extra_decorations);
3297
3298 ImGui::Checkbox(label: "Track", v: &enable_track);
3299 ImGui::PushItemWidth(item_width: 100);
3300 ImGui::SameLine(offset_from_start_x: 140); enable_track |= ImGui::DragInt(label: "##item", v: &track_item, v_speed: 0.25f, v_min: 0, v_max: 99, format: "Item = %d");
3301
3302 bool scroll_to_off = ImGui::Button(label: "Scroll Offset");
3303 ImGui::SameLine(offset_from_start_x: 140); scroll_to_off |= ImGui::DragFloat(label: "##off", v: &scroll_to_off_px, v_speed: 1.00f, v_min: 0, FLT_MAX, format: "+%.0f px");
3304
3305 bool scroll_to_pos = ImGui::Button(label: "Scroll To Pos");
3306 ImGui::SameLine(offset_from_start_x: 140); scroll_to_pos |= ImGui::DragFloat(label: "##pos", v: &scroll_to_pos_px, v_speed: 1.00f, v_min: -10, FLT_MAX, format: "X/Y = %.0f px");
3307 ImGui::PopItemWidth();
3308
3309 if (scroll_to_off || scroll_to_pos)
3310 enable_track = false;
3311
3312 ImGuiStyle& style = ImGui::GetStyle();
3313 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
3314 if (child_w < 1.0f)
3315 child_w = 1.0f;
3316 ImGui::PushID(str_id: "##VerticalScrolling");
3317 for (int i = 0; i < 5; i++)
3318 {
3319 if (i > 0) ImGui::SameLine();
3320 ImGui::BeginGroup();
3321 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
3322 ImGui::TextUnformatted(text: names[i]);
3323
3324 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
3325 const ImGuiID child_id = ImGui::GetID(ptr_id: (void*)(intptr_t)i);
3326 const bool child_is_visible = ImGui::BeginChild(id: child_id, size: ImVec2(child_w, 200.0f), child_flags: ImGuiChildFlags_Border, window_flags: child_flags);
3327 if (ImGui::BeginMenuBar())
3328 {
3329 ImGui::TextUnformatted(text: "abc");
3330 ImGui::EndMenuBar();
3331 }
3332 if (scroll_to_off)
3333 ImGui::SetScrollY(scroll_to_off_px);
3334 if (scroll_to_pos)
3335 ImGui::SetScrollFromPosY(local_y: ImGui::GetCursorStartPos().y + scroll_to_pos_px, center_y_ratio: i * 0.25f);
3336 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
3337 {
3338 for (int item = 0; item < 100; item++)
3339 {
3340 if (enable_track && item == track_item)
3341 {
3342 ImGui::TextColored(col: ImVec4(1, 1, 0, 1), fmt: "Item %d", item);
3343 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
3344 }
3345 else
3346 {
3347 ImGui::Text(fmt: "Item %d", item);
3348 }
3349 }
3350 }
3351 float scroll_y = ImGui::GetScrollY();
3352 float scroll_max_y = ImGui::GetScrollMaxY();
3353 ImGui::EndChild();
3354 ImGui::Text(fmt: "%.0f/%.0f", scroll_y, scroll_max_y);
3355 ImGui::EndGroup();
3356 }
3357 ImGui::PopID();
3358
3359 // Horizontal scroll functions
3360 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
3361 ImGui::Spacing();
3362 HelpMarker(
3363 desc: "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
3364 "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
3365 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
3366 "equivalent SetScrollFromPosY(+1) wouldn't.");
3367 ImGui::PushID(str_id: "##HorizontalScrolling");
3368 for (int i = 0; i < 5; i++)
3369 {
3370 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
3371 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
3372 ImGuiID child_id = ImGui::GetID(ptr_id: (void*)(intptr_t)i);
3373 bool child_is_visible = ImGui::BeginChild(id: child_id, size: ImVec2(-100, child_height), child_flags: ImGuiChildFlags_Border, window_flags: child_flags);
3374 if (scroll_to_off)
3375 ImGui::SetScrollX(scroll_to_off_px);
3376 if (scroll_to_pos)
3377 ImGui::SetScrollFromPosX(local_x: ImGui::GetCursorStartPos().x + scroll_to_pos_px, center_x_ratio: i * 0.25f);
3378 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
3379 {
3380 for (int item = 0; item < 100; item++)
3381 {
3382 if (item > 0)
3383 ImGui::SameLine();
3384 if (enable_track && item == track_item)
3385 {
3386 ImGui::TextColored(col: ImVec4(1, 1, 0, 1), fmt: "Item %d", item);
3387 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
3388 }
3389 else
3390 {
3391 ImGui::Text(fmt: "Item %d", item);
3392 }
3393 }
3394 }
3395 float scroll_x = ImGui::GetScrollX();
3396 float scroll_max_x = ImGui::GetScrollMaxX();
3397 ImGui::EndChild();
3398 ImGui::SameLine();
3399 const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
3400 ImGui::Text(fmt: "%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
3401 ImGui::Spacing();
3402 }
3403 ImGui::PopID();
3404
3405 // Miscellaneous Horizontal Scrolling Demo
3406 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
3407 HelpMarker(
3408 desc: "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
3409 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
3410 static int lines = 7;
3411 ImGui::SliderInt(label: "Lines", v: &lines, v_min: 1, v_max: 15);
3412 ImGui::PushStyleVar(idx: ImGuiStyleVar_FrameRounding, val: 3.0f);
3413 ImGui::PushStyleVar(idx: ImGuiStyleVar_FramePadding, val: ImVec2(2.0f, 1.0f));
3414 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
3415 ImGui::BeginChild(str_id: "scrolling", size: scrolling_child_size, child_flags: ImGuiChildFlags_Border, window_flags: ImGuiWindowFlags_HorizontalScrollbar);
3416 for (int line = 0; line < lines; line++)
3417 {
3418 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
3419 // If you want to create your own time line for a real application you may be better off manipulating
3420 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
3421 // yourself. You may also want to use the lower-level ImDrawList API.
3422 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
3423 for (int n = 0; n < num_buttons; n++)
3424 {
3425 if (n > 0) ImGui::SameLine();
3426 ImGui::PushID(int_id: n + line * 1000);
3427 char num_buf[16];
3428 sprintf(s: num_buf, format: "%d", n);
3429 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
3430 float hue = n * 0.05f;
3431 ImGui::PushStyleColor(idx: ImGuiCol_Button, col: (ImVec4)ImColor::HSV(h: hue, s: 0.6f, v: 0.6f));
3432 ImGui::PushStyleColor(idx: ImGuiCol_ButtonHovered, col: (ImVec4)ImColor::HSV(h: hue, s: 0.7f, v: 0.7f));
3433 ImGui::PushStyleColor(idx: ImGuiCol_ButtonActive, col: (ImVec4)ImColor::HSV(h: hue, s: 0.8f, v: 0.8f));
3434 ImGui::Button(label, size: ImVec2(40.0f + sinf(x: (float)(line + n)) * 20.0f, 0.0f));
3435 ImGui::PopStyleColor(count: 3);
3436 ImGui::PopID();
3437 }
3438 }
3439 float scroll_x = ImGui::GetScrollX();
3440 float scroll_max_x = ImGui::GetScrollMaxX();
3441 ImGui::EndChild();
3442 ImGui::PopStyleVar(count: 2);
3443 float scroll_x_delta = 0.0f;
3444 ImGui::SmallButton(label: "<<");
3445 if (ImGui::IsItemActive())
3446 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
3447 ImGui::SameLine();
3448 ImGui::Text(fmt: "Scroll from code"); ImGui::SameLine();
3449 ImGui::SmallButton(label: ">>");
3450 if (ImGui::IsItemActive())
3451 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
3452 ImGui::SameLine();
3453 ImGui::Text(fmt: "%.0f/%.0f", scroll_x, scroll_max_x);
3454 if (scroll_x_delta != 0.0f)
3455 {
3456 // Demonstrate a trick: you can use Begin to set yourself in the context of another window
3457 // (here we are already out of your child window)
3458 ImGui::BeginChild(str_id: "scrolling");
3459 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
3460 ImGui::EndChild();
3461 }
3462 ImGui::Spacing();
3463
3464 static bool show_horizontal_contents_size_demo_window = false;
3465 ImGui::Checkbox(label: "Show Horizontal contents size demo window", v: &show_horizontal_contents_size_demo_window);
3466
3467 if (show_horizontal_contents_size_demo_window)
3468 {
3469 static bool show_h_scrollbar = true;
3470 static bool show_button = true;
3471 static bool show_tree_nodes = true;
3472 static bool show_text_wrapped = false;
3473 static bool show_columns = true;
3474 static bool show_tab_bar = true;
3475 static bool show_child = false;
3476 static bool explicit_content_size = false;
3477 static float contents_size_x = 300.0f;
3478 if (explicit_content_size)
3479 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
3480 ImGui::Begin(name: "Horizontal contents size demo window", p_open: &show_horizontal_contents_size_demo_window, flags: show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
3481 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
3482 ImGui::PushStyleVar(idx: ImGuiStyleVar_ItemSpacing, val: ImVec2(2, 0));
3483 ImGui::PushStyleVar(idx: ImGuiStyleVar_FramePadding, val: ImVec2(2, 0));
3484 HelpMarker(
3485 desc: "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
3486 "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
3487 ImGui::Checkbox(label: "H-scrollbar", v: &show_h_scrollbar);
3488 ImGui::Checkbox(label: "Button", v: &show_button); // Will grow contents size (unless explicitly overwritten)
3489 ImGui::Checkbox(label: "Tree nodes", v: &show_tree_nodes); // Will grow contents size and display highlight over full width
3490 ImGui::Checkbox(label: "Text wrapped", v: &show_text_wrapped);// Will grow and use contents size
3491 ImGui::Checkbox(label: "Columns", v: &show_columns); // Will use contents size
3492 ImGui::Checkbox(label: "Tab bar", v: &show_tab_bar); // Will use contents size
3493 ImGui::Checkbox(label: "Child", v: &show_child); // Will grow and use contents size
3494 ImGui::Checkbox(label: "Explicit content size", v: &explicit_content_size);
3495 ImGui::Text(fmt: "Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
3496 if (explicit_content_size)
3497 {
3498 ImGui::SameLine();
3499 ImGui::SetNextItemWidth(100);
3500 ImGui::DragFloat(label: "##csx", v: &contents_size_x);
3501 ImVec2 p = ImGui::GetCursorScreenPos();
3502 ImGui::GetWindowDrawList()->AddRectFilled(p_min: p, p_max: ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
3503 ImGui::GetWindowDrawList()->AddRectFilled(p_min: ImVec2(p.x + contents_size_x - 10, p.y), p_max: ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
3504 ImGui::Dummy(size: ImVec2(0, 10));
3505 }
3506 ImGui::PopStyleVar(count: 2);
3507 ImGui::Separator();
3508 if (show_button)
3509 {
3510 ImGui::Button(label: "this is a 300-wide button", size: ImVec2(300, 0));
3511 }
3512 if (show_tree_nodes)
3513 {
3514 bool open = true;
3515 if (ImGui::TreeNode(label: "this is a tree node"))
3516 {
3517 if (ImGui::TreeNode(label: "another one of those tree node..."))
3518 {
3519 ImGui::Text(fmt: "Some tree contents");
3520 ImGui::TreePop();
3521 }
3522 ImGui::TreePop();
3523 }
3524 ImGui::CollapsingHeader(label: "CollapsingHeader", p_visible: &open);
3525 }
3526 if (show_text_wrapped)
3527 {
3528 ImGui::TextWrapped(fmt: "This text should automatically wrap on the edge of the work rectangle.");
3529 }
3530 if (show_columns)
3531 {
3532 ImGui::Text(fmt: "Tables:");
3533 if (ImGui::BeginTable(str_id: "table", column: 4, flags: ImGuiTableFlags_Borders))
3534 {
3535 for (int n = 0; n < 4; n++)
3536 {
3537 ImGui::TableNextColumn();
3538 ImGui::Text(fmt: "Width %.2f", ImGui::GetContentRegionAvail().x);
3539 }
3540 ImGui::EndTable();
3541 }
3542 ImGui::Text(fmt: "Columns:");
3543 ImGui::Columns(count: 4);
3544 for (int n = 0; n < 4; n++)
3545 {
3546 ImGui::Text(fmt: "Width %.2f", ImGui::GetColumnWidth());
3547 ImGui::NextColumn();
3548 }
3549 ImGui::Columns(count: 1);
3550 }
3551 if (show_tab_bar && ImGui::BeginTabBar(str_id: "Hello"))
3552 {
3553 if (ImGui::BeginTabItem(label: "OneOneOne")) { ImGui::EndTabItem(); }
3554 if (ImGui::BeginTabItem(label: "TwoTwoTwo")) { ImGui::EndTabItem(); }
3555 if (ImGui::BeginTabItem(label: "ThreeThreeThree")) { ImGui::EndTabItem(); }
3556 if (ImGui::BeginTabItem(label: "FourFourFour")) { ImGui::EndTabItem(); }
3557 ImGui::EndTabBar();
3558 }
3559 if (show_child)
3560 {
3561 ImGui::BeginChild(str_id: "child", size: ImVec2(0, 0), child_flags: ImGuiChildFlags_Border);
3562 ImGui::EndChild();
3563 }
3564 ImGui::End();
3565 }
3566
3567 ImGui::TreePop();
3568 }
3569
3570 IMGUI_DEMO_MARKER("Layout/Clipping");
3571 if (ImGui::TreeNode(label: "Clipping"))
3572 {
3573 static ImVec2 size(100.0f, 100.0f);
3574 static ImVec2 offset(30.0f, 30.0f);
3575 ImGui::DragFloat2(label: "size", v: (float*)&size, v_speed: 0.5f, v_min: 1.0f, v_max: 200.0f, format: "%.0f");
3576 ImGui::TextWrapped(fmt: "(Click and drag to scroll)");
3577
3578 HelpMarker(
3579 desc: "(Left) Using ImGui::PushClipRect():\n"
3580 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
3581 "(use this if you want your clipping rectangle to affect interactions)\n\n"
3582 "(Center) Using ImDrawList::PushClipRect():\n"
3583 "Will alter ImDrawList rendering only.\n"
3584 "(use this as a shortcut if you are only using ImDrawList calls)\n\n"
3585 "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
3586 "Will alter only this specific ImDrawList::AddText() rendering.\n"
3587 "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
3588
3589 for (int n = 0; n < 3; n++)
3590 {
3591 if (n > 0)
3592 ImGui::SameLine();
3593
3594 ImGui::PushID(int_id: n);
3595 ImGui::InvisibleButton(str_id: "##canvas", size);
3596 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(button: ImGuiMouseButton_Left))
3597 {
3598 offset.x += ImGui::GetIO().MouseDelta.x;
3599 offset.y += ImGui::GetIO().MouseDelta.y;
3600 }
3601 ImGui::PopID();
3602 if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
3603 continue;
3604
3605 const ImVec2 p0 = ImGui::GetItemRectMin();
3606 const ImVec2 p1 = ImGui::GetItemRectMax();
3607 const char* text_str = "Line 1 hello\nLine 2 clip me!";
3608 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
3609 ImDrawList* draw_list = ImGui::GetWindowDrawList();
3610 switch (n)
3611 {
3612 case 0:
3613 ImGui::PushClipRect(clip_rect_min: p0, clip_rect_max: p1, intersect_with_current_clip_rect: true);
3614 draw_list->AddRectFilled(p_min: p0, p_max: p1, IM_COL32(90, 90, 120, 255));
3615 draw_list->AddText(pos: text_pos, IM_COL32_WHITE, text_begin: text_str);
3616 ImGui::PopClipRect();
3617 break;
3618 case 1:
3619 draw_list->PushClipRect(clip_rect_min: p0, clip_rect_max: p1, intersect_with_current_clip_rect: true);
3620 draw_list->AddRectFilled(p_min: p0, p_max: p1, IM_COL32(90, 90, 120, 255));
3621 draw_list->AddText(pos: text_pos, IM_COL32_WHITE, text_begin: text_str);
3622 draw_list->PopClipRect();
3623 break;
3624 case 2:
3625 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
3626 draw_list->AddRectFilled(p_min: p0, p_max: p1, IM_COL32(90, 90, 120, 255));
3627 draw_list->AddText(font: ImGui::GetFont(), font_size: ImGui::GetFontSize(), pos: text_pos, IM_COL32_WHITE, text_begin: text_str, NULL, wrap_width: 0.0f, cpu_fine_clip_rect: &clip_rect);
3628 break;
3629 }
3630 }
3631
3632 ImGui::TreePop();
3633 }
3634
3635 IMGUI_DEMO_MARKER("Layout/Overlap Mode");
3636 if (ImGui::TreeNode(label: "Overlap Mode"))
3637 {
3638 static bool enable_allow_overlap = true;
3639
3640 HelpMarker(
3641 desc: "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
3642 "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
3643 "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
3644 ImGui::Checkbox(label: "Enable AllowOverlap", v: &enable_allow_overlap);
3645
3646 ImVec2 button1_pos = ImGui::GetCursorScreenPos();
3647 ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
3648 if (enable_allow_overlap)
3649 ImGui::SetNextItemAllowOverlap();
3650 ImGui::Button(label: "Button 1", size: ImVec2(80, 80));
3651 ImGui::SetCursorScreenPos(button2_pos);
3652 ImGui::Button(label: "Button 2", size: ImVec2(80, 80));
3653
3654 // This is typically used with width-spanning items.
3655 // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
3656 // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
3657 if (enable_allow_overlap)
3658 ImGui::SetNextItemAllowOverlap();
3659 ImGui::Selectable(label: "Some Selectable", selected: false);
3660 ImGui::SameLine();
3661 ImGui::SmallButton(label: "++");
3662
3663 ImGui::TreePop();
3664 }
3665}
3666
3667static void ShowDemoWindowPopups()
3668{
3669 IMGUI_DEMO_MARKER("Popups");
3670 if (!ImGui::CollapsingHeader(label: "Popups & Modal windows"))
3671 return;
3672
3673 // The properties of popups windows are:
3674 // - They block normal mouse hovering detection outside them. (*)
3675 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
3676 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
3677 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
3678 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
3679 // when normally blocked by a popup.
3680 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
3681 // popups at any time.
3682
3683 // Typical use for regular windows:
3684 // 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();
3685 // Typical use for popups:
3686 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
3687
3688 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
3689 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
3690
3691 IMGUI_DEMO_MARKER("Popups/Popups");
3692 if (ImGui::TreeNode(label: "Popups"))
3693 {
3694 ImGui::TextWrapped(
3695 fmt: "When a popup is active, it inhibits interacting with windows that are behind the popup. "
3696 "Clicking outside the popup closes it.");
3697
3698 static int selected_fish = -1;
3699 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
3700 static bool toggles[] = { true, false, false, false, false };
3701
3702 // Simple selection popup (if you want to show the current selection inside the Button itself,
3703 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
3704 if (ImGui::Button(label: "Select.."))
3705 ImGui::OpenPopup(str_id: "my_select_popup");
3706 ImGui::SameLine();
3707 ImGui::TextUnformatted(text: selected_fish == -1 ? "<None>" : names[selected_fish]);
3708 if (ImGui::BeginPopup(str_id: "my_select_popup"))
3709 {
3710 ImGui::SeparatorText(label: "Aquarium");
3711 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3712 if (ImGui::Selectable(label: names[i]))
3713 selected_fish = i;
3714 ImGui::EndPopup();
3715 }
3716
3717 // Showing a menu with toggles
3718 if (ImGui::Button(label: "Toggle.."))
3719 ImGui::OpenPopup(str_id: "my_toggle_popup");
3720 if (ImGui::BeginPopup(str_id: "my_toggle_popup"))
3721 {
3722 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3723 ImGui::MenuItem(label: names[i], shortcut: "", p_selected: &toggles[i]);
3724 if (ImGui::BeginMenu(label: "Sub-menu"))
3725 {
3726 ImGui::MenuItem(label: "Click me");
3727 ImGui::EndMenu();
3728 }
3729
3730 ImGui::Separator();
3731 ImGui::Text(fmt: "Tooltip here");
3732 ImGui::SetItemTooltip("I am a tooltip over a popup");
3733
3734 if (ImGui::Button(label: "Stacked Popup"))
3735 ImGui::OpenPopup(str_id: "another popup");
3736 if (ImGui::BeginPopup(str_id: "another popup"))
3737 {
3738 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3739 ImGui::MenuItem(label: names[i], shortcut: "", p_selected: &toggles[i]);
3740 if (ImGui::BeginMenu(label: "Sub-menu"))
3741 {
3742 ImGui::MenuItem(label: "Click me");
3743 if (ImGui::Button(label: "Stacked Popup"))
3744 ImGui::OpenPopup(str_id: "another popup");
3745 if (ImGui::BeginPopup(str_id: "another popup"))
3746 {
3747 ImGui::Text(fmt: "I am the last one here.");
3748 ImGui::EndPopup();
3749 }
3750 ImGui::EndMenu();
3751 }
3752 ImGui::EndPopup();
3753 }
3754 ImGui::EndPopup();
3755 }
3756
3757 // Call the more complete ShowExampleMenuFile which we use in various places of this demo
3758 if (ImGui::Button(label: "With a menu.."))
3759 ImGui::OpenPopup(str_id: "my_file_popup");
3760 if (ImGui::BeginPopup(str_id: "my_file_popup", flags: ImGuiWindowFlags_MenuBar))
3761 {
3762 if (ImGui::BeginMenuBar())
3763 {
3764 if (ImGui::BeginMenu(label: "File"))
3765 {
3766 ShowExampleMenuFile();
3767 ImGui::EndMenu();
3768 }
3769 if (ImGui::BeginMenu(label: "Edit"))
3770 {
3771 ImGui::MenuItem(label: "Dummy");
3772 ImGui::EndMenu();
3773 }
3774 ImGui::EndMenuBar();
3775 }
3776 ImGui::Text(fmt: "Hello from popup!");
3777 ImGui::Button(label: "This is a dummy button..");
3778 ImGui::EndPopup();
3779 }
3780
3781 ImGui::TreePop();
3782 }
3783
3784 IMGUI_DEMO_MARKER("Popups/Context menus");
3785 if (ImGui::TreeNode(label: "Context menus"))
3786 {
3787 HelpMarker(desc: "\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
3788
3789 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
3790 // if (id == 0)
3791 // id = GetItemID(); // Use last item id
3792 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
3793 // OpenPopup(id);
3794 // return BeginPopup(id);
3795 // For advanced uses you may want to replicate and customize this code.
3796 // See more details in BeginPopupContextItem().
3797
3798 // Example 1
3799 // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
3800 // and BeginPopupContextItem() will use the last item ID as the popup ID.
3801 {
3802 const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
3803 static int selected = -1;
3804 for (int n = 0; n < 5; n++)
3805 {
3806 if (ImGui::Selectable(label: names[n], selected: selected == n))
3807 selected = n;
3808 if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
3809 {
3810 selected = n;
3811 ImGui::Text(fmt: "This a popup for \"%s\"!", names[n]);
3812 if (ImGui::Button(label: "Close"))
3813 ImGui::CloseCurrentPopup();
3814 ImGui::EndPopup();
3815 }
3816 ImGui::SetItemTooltip("Right-click to open popup");
3817 }
3818 }
3819
3820 // Example 2
3821 // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
3822 // Using an explicit identifier is also convenient if you want to activate the popups from different locations.
3823 {
3824 HelpMarker(desc: "Text() elements don't have stable identifiers so we need to provide one.");
3825 static float value = 0.5f;
3826 ImGui::Text(fmt: "Value = %.3f <-- (1) right-click this text", value);
3827 if (ImGui::BeginPopupContextItem(str_id: "my popup"))
3828 {
3829 if (ImGui::Selectable(label: "Set to zero")) value = 0.0f;
3830 if (ImGui::Selectable(label: "Set to PI")) value = 3.1415f;
3831 ImGui::SetNextItemWidth(-FLT_MIN);
3832 ImGui::DragFloat(label: "##Value", v: &value, v_speed: 0.1f, v_min: 0.0f, v_max: 0.0f);
3833 ImGui::EndPopup();
3834 }
3835
3836 // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
3837 // Here we make it that right-clicking this other text element opens the same popup as above.
3838 // The popup itself will be submitted by the code above.
3839 ImGui::Text(fmt: "(2) Or right-click this text");
3840 ImGui::OpenPopupOnItemClick(str_id: "my popup", popup_flags: ImGuiPopupFlags_MouseButtonRight);
3841
3842 // Back to square one: manually open the same popup.
3843 if (ImGui::Button(label: "(3) Or click this button"))
3844 ImGui::OpenPopup(str_id: "my popup");
3845 }
3846
3847 // Example 3
3848 // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
3849 // we need to make sure your item identifier is stable.
3850 // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
3851 {
3852 HelpMarker(desc: "Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
3853 static char name[32] = "Label1";
3854 char buf[64];
3855 sprintf(s: buf, format: "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
3856 ImGui::Button(label: buf);
3857 if (ImGui::BeginPopupContextItem())
3858 {
3859 ImGui::Text(fmt: "Edit name:");
3860 ImGui::InputText(label: "##edit", buf: name, IM_ARRAYSIZE(name));
3861 if (ImGui::Button(label: "Close"))
3862 ImGui::CloseCurrentPopup();
3863 ImGui::EndPopup();
3864 }
3865 ImGui::SameLine(); ImGui::Text(fmt: "(<-- right-click here)");
3866 }
3867
3868 ImGui::TreePop();
3869 }
3870
3871 IMGUI_DEMO_MARKER("Popups/Modals");
3872 if (ImGui::TreeNode(label: "Modals"))
3873 {
3874 ImGui::TextWrapped(fmt: "Modal windows are like popups but the user cannot close them by clicking outside.");
3875
3876 if (ImGui::Button(label: "Delete.."))
3877 ImGui::OpenPopup(str_id: "Delete?");
3878
3879 // Always center this window when appearing
3880 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
3881 ImGui::SetNextWindowPos(pos: center, cond: ImGuiCond_Appearing, pivot: ImVec2(0.5f, 0.5f));
3882
3883 if (ImGui::BeginPopupModal(name: "Delete?", NULL, flags: ImGuiWindowFlags_AlwaysAutoResize))
3884 {
3885 ImGui::Text(fmt: "All those beautiful files will be deleted.\nThis operation cannot be undone!");
3886 ImGui::Separator();
3887
3888 //static int unused_i = 0;
3889 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
3890
3891 static bool dont_ask_me_next_time = false;
3892 ImGui::PushStyleVar(idx: ImGuiStyleVar_FramePadding, val: ImVec2(0, 0));
3893 ImGui::Checkbox(label: "Don't ask me next time", v: &dont_ask_me_next_time);
3894 ImGui::PopStyleVar();
3895
3896 if (ImGui::Button(label: "OK", size: ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3897 ImGui::SetItemDefaultFocus();
3898 ImGui::SameLine();
3899 if (ImGui::Button(label: "Cancel", size: ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3900 ImGui::EndPopup();
3901 }
3902
3903 if (ImGui::Button(label: "Stacked modals.."))
3904 ImGui::OpenPopup(str_id: "Stacked 1");
3905 if (ImGui::BeginPopupModal(name: "Stacked 1", NULL, flags: ImGuiWindowFlags_MenuBar))
3906 {
3907 if (ImGui::BeginMenuBar())
3908 {
3909 if (ImGui::BeginMenu(label: "File"))
3910 {
3911 if (ImGui::MenuItem(label: "Some menu item")) {}
3912 ImGui::EndMenu();
3913 }
3914 ImGui::EndMenuBar();
3915 }
3916 ImGui::Text(fmt: "Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
3917
3918 // Testing behavior of widgets stacking their own regular popups over the modal.
3919 static int item = 1;
3920 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
3921 ImGui::Combo(label: "Combo", current_item: &item, items_separated_by_zeros: "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
3922 ImGui::ColorEdit4(label: "color", col: color);
3923
3924 if (ImGui::Button(label: "Add another modal.."))
3925 ImGui::OpenPopup(str_id: "Stacked 2");
3926
3927 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
3928 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
3929 // of the bool actually doesn't matter here.
3930 bool unused_open = true;
3931 if (ImGui::BeginPopupModal(name: "Stacked 2", p_open: &unused_open))
3932 {
3933 ImGui::Text(fmt: "Hello from Stacked The Second!");
3934 if (ImGui::Button(label: "Close"))
3935 ImGui::CloseCurrentPopup();
3936 ImGui::EndPopup();
3937 }
3938
3939 if (ImGui::Button(label: "Close"))
3940 ImGui::CloseCurrentPopup();
3941 ImGui::EndPopup();
3942 }
3943
3944 ImGui::TreePop();
3945 }
3946
3947 IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
3948 if (ImGui::TreeNode(label: "Menus inside a regular window"))
3949 {
3950 ImGui::TextWrapped(fmt: "Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
3951 ImGui::Separator();
3952
3953 ImGui::MenuItem(label: "Menu item", shortcut: "CTRL+M");
3954 if (ImGui::BeginMenu(label: "Menu inside a regular window"))
3955 {
3956 ShowExampleMenuFile();
3957 ImGui::EndMenu();
3958 }
3959 ImGui::Separator();
3960 ImGui::TreePop();
3961 }
3962}
3963
3964// Dummy data structure that we use for the Table demo.
3965// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
3966namespace
3967{
3968// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
3969// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
3970// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
3971// If you don't use sorting, you will generally never care about giving column an ID!
3972enum MyItemColumnID
3973{
3974 MyItemColumnID_ID,
3975 MyItemColumnID_Name,
3976 MyItemColumnID_Action,
3977 MyItemColumnID_Quantity,
3978 MyItemColumnID_Description
3979};
3980
3981struct MyItem
3982{
3983 int ID;
3984 const char* Name;
3985 int Quantity;
3986
3987 // We have a problem which is affecting _only this demo_ and should not affect your code:
3988 // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
3989 // however qsort doesn't allow passing user data to comparing function.
3990 // As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
3991 // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
3992 // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
3993 // very often by the sorting algorithm it would be a little wasteful.
3994 static const ImGuiTableSortSpecs* s_current_sort_specs;
3995
3996 static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
3997 {
3998 s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
3999 if (items_count > 1)
4000 qsort(base: items, nmemb: (size_t)items_count, size: sizeof(items[0]), compar: MyItem::CompareWithSortSpecs);
4001 s_current_sort_specs = NULL;
4002 }
4003
4004 // Compare function to be used by qsort()
4005 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
4006 {
4007 const MyItem* a = (const MyItem*)lhs;
4008 const MyItem* b = (const MyItem*)rhs;
4009 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
4010 {
4011 // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
4012 // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
4013 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
4014 int delta = 0;
4015 switch (sort_spec->ColumnUserID)
4016 {
4017 case MyItemColumnID_ID: delta = (a->ID - b->ID); break;
4018 case MyItemColumnID_Name: delta = (strcmp(s1: a->Name, s2: b->Name)); break;
4019 case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break;
4020 case MyItemColumnID_Description: delta = (strcmp(s1: a->Name, s2: b->Name)); break;
4021 default: IM_ASSERT(0); break;
4022 }
4023 if (delta > 0)
4024 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
4025 if (delta < 0)
4026 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
4027 }
4028
4029 // qsort() is instable so always return a way to differenciate items.
4030 // Your own compare function may want to avoid fallback on implicit sort specs.
4031 // e.g. a Name compare if it wasn't already part of the sort specs.
4032 return (a->ID - b->ID);
4033 }
4034};
4035const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
4036}
4037
4038// Make the UI compact because there are so many fields
4039static void PushStyleCompact()
4040{
4041 ImGuiStyle& style = ImGui::GetStyle();
4042 ImGui::PushStyleVar(idx: ImGuiStyleVar_FramePadding, val: ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f)));
4043 ImGui::PushStyleVar(idx: ImGuiStyleVar_ItemSpacing, val: ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f)));
4044}
4045
4046static void PopStyleCompact()
4047{
4048 ImGui::PopStyleVar(count: 2);
4049}
4050
4051// Show a combo box with a choice of sizing policies
4052static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
4053{
4054 struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
4055 static const EnumDesc policies[] =
4056 {
4057 { .Value: ImGuiTableFlags_None, .Name: "Default", .Tooltip: "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." },
4058 { .Value: ImGuiTableFlags_SizingFixedFit, .Name: "ImGuiTableFlags_SizingFixedFit", .Tooltip: "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
4059 { .Value: ImGuiTableFlags_SizingFixedSame, .Name: "ImGuiTableFlags_SizingFixedSame", .Tooltip: "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
4060 { .Value: ImGuiTableFlags_SizingStretchProp, .Name: "ImGuiTableFlags_SizingStretchProp", .Tooltip: "Columns default to _WidthStretch with weights proportional to their widths." },
4061 { .Value: ImGuiTableFlags_SizingStretchSame, .Name: "ImGuiTableFlags_SizingStretchSame", .Tooltip: "Columns default to _WidthStretch with same weights." }
4062 };
4063 int idx;
4064 for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
4065 if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
4066 break;
4067 const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen(s: "ImGuiTableFlags") : 0) : "";
4068 if (ImGui::BeginCombo(label: "Sizing Policy", preview_value: preview_text))
4069 {
4070 for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
4071 if (ImGui::Selectable(label: policies[n].Name, selected: idx == n))
4072 *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
4073 ImGui::EndCombo();
4074 }
4075 ImGui::SameLine();
4076 ImGui::TextDisabled(fmt: "(?)");
4077 if (ImGui::BeginItemTooltip())
4078 {
4079 ImGui::PushTextWrapPos(wrap_local_pos_x: ImGui::GetFontSize() * 50.0f);
4080 for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
4081 {
4082 ImGui::Separator();
4083 ImGui::Text(fmt: "%s:", policies[m].Name);
4084 ImGui::Separator();
4085 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
4086 ImGui::TextUnformatted(text: policies[m].Tooltip);
4087 }
4088 ImGui::PopTextWrapPos();
4089 ImGui::EndTooltip();
4090 }
4091}
4092
4093static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
4094{
4095 ImGui::CheckboxFlags(label: "_Disabled", flags: p_flags, flags_value: ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker(desc: "Master disable flag (also hide from context menu)");
4096 ImGui::CheckboxFlags(label: "_DefaultHide", flags: p_flags, flags_value: ImGuiTableColumnFlags_DefaultHide);
4097 ImGui::CheckboxFlags(label: "_DefaultSort", flags: p_flags, flags_value: ImGuiTableColumnFlags_DefaultSort);
4098 if (ImGui::CheckboxFlags(label: "_WidthStretch", flags: p_flags, flags_value: ImGuiTableColumnFlags_WidthStretch))
4099 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
4100 if (ImGui::CheckboxFlags(label: "_WidthFixed", flags: p_flags, flags_value: ImGuiTableColumnFlags_WidthFixed))
4101 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
4102 ImGui::CheckboxFlags(label: "_NoResize", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoResize);
4103 ImGui::CheckboxFlags(label: "_NoReorder", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoReorder);
4104 ImGui::CheckboxFlags(label: "_NoHide", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoHide);
4105 ImGui::CheckboxFlags(label: "_NoClip", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoClip);
4106 ImGui::CheckboxFlags(label: "_NoSort", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoSort);
4107 ImGui::CheckboxFlags(label: "_NoSortAscending", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoSortAscending);
4108 ImGui::CheckboxFlags(label: "_NoSortDescending", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoSortDescending);
4109 ImGui::CheckboxFlags(label: "_NoHeaderLabel", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoHeaderLabel);
4110 ImGui::CheckboxFlags(label: "_NoHeaderWidth", flags: p_flags, flags_value: ImGuiTableColumnFlags_NoHeaderWidth);
4111 ImGui::CheckboxFlags(label: "_PreferSortAscending", flags: p_flags, flags_value: ImGuiTableColumnFlags_PreferSortAscending);
4112 ImGui::CheckboxFlags(label: "_PreferSortDescending", flags: p_flags, flags_value: ImGuiTableColumnFlags_PreferSortDescending);
4113 ImGui::CheckboxFlags(label: "_IndentEnable", flags: p_flags, flags_value: ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker(desc: "Default for column 0");
4114 ImGui::CheckboxFlags(label: "_IndentDisable", flags: p_flags, flags_value: ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker(desc: "Default for column >0");
4115 ImGui::CheckboxFlags(label: "_AngledHeader", flags: p_flags, flags_value: ImGuiTableColumnFlags_AngledHeader);
4116}
4117
4118static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
4119{
4120 ImGui::CheckboxFlags(label: "_IsEnabled", flags: &flags, flags_value: ImGuiTableColumnFlags_IsEnabled);
4121 ImGui::CheckboxFlags(label: "_IsVisible", flags: &flags, flags_value: ImGuiTableColumnFlags_IsVisible);
4122 ImGui::CheckboxFlags(label: "_IsSorted", flags: &flags, flags_value: ImGuiTableColumnFlags_IsSorted);
4123 ImGui::CheckboxFlags(label: "_IsHovered", flags: &flags, flags_value: ImGuiTableColumnFlags_IsHovered);
4124}
4125
4126static void ShowDemoWindowTables()
4127{
4128 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
4129 IMGUI_DEMO_MARKER("Tables");
4130 if (!ImGui::CollapsingHeader(label: "Tables & Columns"))
4131 return;
4132
4133 // Using those as a base value to create width/height that are factor of the size of our font
4134 const float TEXT_BASE_WIDTH = ImGui::CalcTextSize(text: "A").x;
4135 const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
4136
4137 ImGui::PushID(str_id: "Tables");
4138
4139 int open_action = -1;
4140 if (ImGui::Button(label: "Expand all"))
4141 open_action = 1;
4142 ImGui::SameLine();
4143 if (ImGui::Button(label: "Collapse all"))
4144 open_action = 0;
4145 ImGui::SameLine();
4146
4147 // Options
4148 static bool disable_indent = false;
4149 ImGui::Checkbox(label: "Disable tree indentation", v: &disable_indent);
4150 ImGui::SameLine();
4151 HelpMarker(desc: "Disable the indenting of tree nodes so demo tables can use the full window width.");
4152 ImGui::Separator();
4153 if (disable_indent)
4154 ImGui::PushStyleVar(idx: ImGuiStyleVar_IndentSpacing, val: 0.0f);
4155
4156 // About Styling of tables
4157 // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
4158 // There are however a few settings that a shared and part of the ImGuiStyle structure:
4159 // style.CellPadding // Padding within each cell
4160 // style.Colors[ImGuiCol_TableHeaderBg] // Table header background
4161 // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders
4162 // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders
4163 // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
4164 // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
4165
4166 // Demos
4167 if (open_action != -1)
4168 ImGui::SetNextItemOpen(is_open: open_action != 0);
4169 IMGUI_DEMO_MARKER("Tables/Basic");
4170 if (ImGui::TreeNode(label: "Basic"))
4171 {
4172 // Here we will showcase three different ways to output a table.
4173 // They are very simple variations of a same thing!
4174
4175 // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
4176 // In many situations, this is the most flexible and easy to use pattern.
4177 HelpMarker(desc: "Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
4178 if (ImGui::BeginTable(str_id: "table1", column: 3))
4179 {
4180 for (int row = 0; row < 4; row++)
4181 {
4182 ImGui::TableNextRow();
4183 for (int column = 0; column < 3; column++)
4184 {
4185 ImGui::TableSetColumnIndex(column_n: column);
4186 ImGui::Text(fmt: "Row %d Column %d", row, column);
4187 }
4188 }
4189 ImGui::EndTable();
4190 }
4191
4192 // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
4193 // This is generally more convenient when you have code manually submitting the contents of each column.
4194 HelpMarker(desc: "Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
4195 if (ImGui::BeginTable(str_id: "table2", column: 3))
4196 {
4197 for (int row = 0; row < 4; row++)
4198 {
4199 ImGui::TableNextRow();
4200 ImGui::TableNextColumn();
4201 ImGui::Text(fmt: "Row %d", row);
4202 ImGui::TableNextColumn();
4203 ImGui::Text(fmt: "Some contents");
4204 ImGui::TableNextColumn();
4205 ImGui::Text(fmt: "123.456");
4206 }
4207 ImGui::EndTable();
4208 }
4209
4210 // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
4211 // as TableNextColumn() will automatically wrap around and create new rows as needed.
4212 // This is generally more convenient when your cells all contains the same type of data.
4213 HelpMarker(
4214 desc: "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
4215 "the same type of contents.\n This is also more similar to the old NextColumn() function of the "
4216 "Columns API, and provided to facilitate the Columns->Tables API transition.");
4217 if (ImGui::BeginTable(str_id: "table3", column: 3))
4218 {
4219 for (int item = 0; item < 14; item++)
4220 {
4221 ImGui::TableNextColumn();
4222 ImGui::Text(fmt: "Item %d", item);
4223 }
4224 ImGui::EndTable();
4225 }
4226
4227 ImGui::TreePop();
4228 }
4229
4230 if (open_action != -1)
4231 ImGui::SetNextItemOpen(is_open: open_action != 0);
4232 IMGUI_DEMO_MARKER("Tables/Borders, background");
4233 if (ImGui::TreeNode(label: "Borders, background"))
4234 {
4235 // Expose a few Borders related flags interactively
4236 enum ContentsType { CT_Text, CT_FillButton };
4237 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
4238 static bool display_headers = false;
4239 static int contents_type = CT_Text;
4240
4241 PushStyleCompact();
4242 ImGui::CheckboxFlags(label: "ImGuiTableFlags_RowBg", flags: &flags, flags_value: ImGuiTableFlags_RowBg);
4243 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Borders", flags: &flags, flags_value: ImGuiTableFlags_Borders);
4244 ImGui::SameLine(); HelpMarker(desc: "ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterH");
4245 ImGui::Indent();
4246
4247 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersH", flags: &flags, flags_value: ImGuiTableFlags_BordersH);
4248 ImGui::Indent();
4249 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuterH", flags: &flags, flags_value: ImGuiTableFlags_BordersOuterH);
4250 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInnerH", flags: &flags, flags_value: ImGuiTableFlags_BordersInnerH);
4251 ImGui::Unindent();
4252
4253 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersV", flags: &flags, flags_value: ImGuiTableFlags_BordersV);
4254 ImGui::Indent();
4255 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuterV", flags: &flags, flags_value: ImGuiTableFlags_BordersOuterV);
4256 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInnerV", flags: &flags, flags_value: ImGuiTableFlags_BordersInnerV);
4257 ImGui::Unindent();
4258
4259 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuter", flags: &flags, flags_value: ImGuiTableFlags_BordersOuter);
4260 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInner", flags: &flags, flags_value: ImGuiTableFlags_BordersInner);
4261 ImGui::Unindent();
4262
4263 ImGui::AlignTextToFramePadding(); ImGui::Text(fmt: "Cell contents:");
4264 ImGui::SameLine(); ImGui::RadioButton(label: "Text", v: &contents_type, v_button: CT_Text);
4265 ImGui::SameLine(); ImGui::RadioButton(label: "FillButton", v: &contents_type, v_button: CT_FillButton);
4266 ImGui::Checkbox(label: "Display headers", v: &display_headers);
4267 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoBordersInBody", flags: &flags, flags_value: ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker(desc: "Disable vertical borders in columns Body (borders will always appear in Headers");
4268 PopStyleCompact();
4269
4270 if (ImGui::BeginTable(str_id: "table1", column: 3, flags))
4271 {
4272 // Display headers so we can inspect their interaction with borders
4273 // (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)
4274 if (display_headers)
4275 {
4276 ImGui::TableSetupColumn(label: "One");
4277 ImGui::TableSetupColumn(label: "Two");
4278 ImGui::TableSetupColumn(label: "Three");
4279 ImGui::TableHeadersRow();
4280 }
4281
4282 for (int row = 0; row < 5; row++)
4283 {
4284 ImGui::TableNextRow();
4285 for (int column = 0; column < 3; column++)
4286 {
4287 ImGui::TableSetColumnIndex(column_n: column);
4288 char buf[32];
4289 sprintf(s: buf, format: "Hello %d,%d", column, row);
4290 if (contents_type == CT_Text)
4291 ImGui::TextUnformatted(text: buf);
4292 else if (contents_type == CT_FillButton)
4293 ImGui::Button(label: buf, size: ImVec2(-FLT_MIN, 0.0f));
4294 }
4295 }
4296 ImGui::EndTable();
4297 }
4298 ImGui::TreePop();
4299 }
4300
4301 if (open_action != -1)
4302 ImGui::SetNextItemOpen(is_open: open_action != 0);
4303 IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
4304 if (ImGui::TreeNode(label: "Resizable, stretch"))
4305 {
4306 // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
4307 // All columns maintain a sizing weight, and they will occupy all available width.
4308 static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
4309 PushStyleCompact();
4310 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags, flags_value: ImGuiTableFlags_Resizable);
4311 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersV", flags: &flags, flags_value: ImGuiTableFlags_BordersV);
4312 ImGui::SameLine(); HelpMarker(
4313 desc: "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
4314 "this is why the resize borders are still showing when unchecking this.");
4315 PopStyleCompact();
4316
4317 if (ImGui::BeginTable(str_id: "table1", column: 3, flags))
4318 {
4319 for (int row = 0; row < 5; row++)
4320 {
4321 ImGui::TableNextRow();
4322 for (int column = 0; column < 3; column++)
4323 {
4324 ImGui::TableSetColumnIndex(column_n: column);
4325 ImGui::Text(fmt: "Hello %d,%d", column, row);
4326 }
4327 }
4328 ImGui::EndTable();
4329 }
4330 ImGui::TreePop();
4331 }
4332
4333 if (open_action != -1)
4334 ImGui::SetNextItemOpen(is_open: open_action != 0);
4335 IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
4336 if (ImGui::TreeNode(label: "Resizable, fixed"))
4337 {
4338 // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
4339 // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
4340 // If there is not enough available width to fit all columns, they will however be resized down.
4341 // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
4342 HelpMarker(
4343 desc: "Using _Resizable + _SizingFixedFit flags.\n"
4344 "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
4345 "Double-click a column border to auto-fit the column to its contents.");
4346 PushStyleCompact();
4347 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
4348 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoHostExtendX", flags: &flags, flags_value: ImGuiTableFlags_NoHostExtendX);
4349 PopStyleCompact();
4350
4351 if (ImGui::BeginTable(str_id: "table1", column: 3, flags))
4352 {
4353 for (int row = 0; row < 5; row++)
4354 {
4355 ImGui::TableNextRow();
4356 for (int column = 0; column < 3; column++)
4357 {
4358 ImGui::TableSetColumnIndex(column_n: column);
4359 ImGui::Text(fmt: "Hello %d,%d", column, row);
4360 }
4361 }
4362 ImGui::EndTable();
4363 }
4364 ImGui::TreePop();
4365 }
4366
4367 if (open_action != -1)
4368 ImGui::SetNextItemOpen(is_open: open_action != 0);
4369 IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
4370 if (ImGui::TreeNode(label: "Resizable, mixed"))
4371 {
4372 HelpMarker(
4373 desc: "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
4374 "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
4375 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4376
4377 if (ImGui::BeginTable(str_id: "table1", column: 3, flags))
4378 {
4379 ImGui::TableSetupColumn(label: "AAA", flags: ImGuiTableColumnFlags_WidthFixed);
4380 ImGui::TableSetupColumn(label: "BBB", flags: ImGuiTableColumnFlags_WidthFixed);
4381 ImGui::TableSetupColumn(label: "CCC", flags: ImGuiTableColumnFlags_WidthStretch);
4382 ImGui::TableHeadersRow();
4383 for (int row = 0; row < 5; row++)
4384 {
4385 ImGui::TableNextRow();
4386 for (int column = 0; column < 3; column++)
4387 {
4388 ImGui::TableSetColumnIndex(column_n: column);
4389 ImGui::Text(fmt: "%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
4390 }
4391 }
4392 ImGui::EndTable();
4393 }
4394 if (ImGui::BeginTable(str_id: "table2", column: 6, flags))
4395 {
4396 ImGui::TableSetupColumn(label: "AAA", flags: ImGuiTableColumnFlags_WidthFixed);
4397 ImGui::TableSetupColumn(label: "BBB", flags: ImGuiTableColumnFlags_WidthFixed);
4398 ImGui::TableSetupColumn(label: "CCC", flags: ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
4399 ImGui::TableSetupColumn(label: "DDD", flags: ImGuiTableColumnFlags_WidthStretch);
4400 ImGui::TableSetupColumn(label: "EEE", flags: ImGuiTableColumnFlags_WidthStretch);
4401 ImGui::TableSetupColumn(label: "FFF", flags: ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
4402 ImGui::TableHeadersRow();
4403 for (int row = 0; row < 5; row++)
4404 {
4405 ImGui::TableNextRow();
4406 for (int column = 0; column < 6; column++)
4407 {
4408 ImGui::TableSetColumnIndex(column_n: column);
4409 ImGui::Text(fmt: "%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
4410 }
4411 }
4412 ImGui::EndTable();
4413 }
4414 ImGui::TreePop();
4415 }
4416
4417 if (open_action != -1)
4418 ImGui::SetNextItemOpen(is_open: open_action != 0);
4419 IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
4420 if (ImGui::TreeNode(label: "Reorderable, hideable, with headers"))
4421 {
4422 HelpMarker(
4423 desc: "Click and drag column headers to reorder columns.\n\n"
4424 "Right-click on a header to open a context menu.");
4425 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
4426 PushStyleCompact();
4427 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags, flags_value: ImGuiTableFlags_Resizable);
4428 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Reorderable", flags: &flags, flags_value: ImGuiTableFlags_Reorderable);
4429 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Hideable", flags: &flags, flags_value: ImGuiTableFlags_Hideable);
4430 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoBordersInBody", flags: &flags, flags_value: ImGuiTableFlags_NoBordersInBody);
4431 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoBordersInBodyUntilResize", flags: &flags, flags_value: ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker(desc: "Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
4432 ImGui::CheckboxFlags(label: "ImGuiTableFlags_HighlightHoveredColumn", flags: &flags, flags_value: ImGuiTableFlags_HighlightHoveredColumn);
4433 PopStyleCompact();
4434
4435 if (ImGui::BeginTable(str_id: "table1", column: 3, flags))
4436 {
4437 // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
4438 // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
4439 ImGui::TableSetupColumn(label: "One");
4440 ImGui::TableSetupColumn(label: "Two");
4441 ImGui::TableSetupColumn(label: "Three");
4442 ImGui::TableHeadersRow();
4443 for (int row = 0; row < 6; row++)
4444 {
4445 ImGui::TableNextRow();
4446 for (int column = 0; column < 3; column++)
4447 {
4448 ImGui::TableSetColumnIndex(column_n: column);
4449 ImGui::Text(fmt: "Hello %d,%d", column, row);
4450 }
4451 }
4452 ImGui::EndTable();
4453 }
4454
4455 // Use outer_size.x == 0.0f instead of default to make the table as tight as possible
4456 // (only valid when no scrolling and no stretch column)
4457 if (ImGui::BeginTable(str_id: "table2", column: 3, flags: flags | ImGuiTableFlags_SizingFixedFit, outer_size: ImVec2(0.0f, 0.0f)))
4458 {
4459 ImGui::TableSetupColumn(label: "One");
4460 ImGui::TableSetupColumn(label: "Two");
4461 ImGui::TableSetupColumn(label: "Three");
4462 ImGui::TableHeadersRow();
4463 for (int row = 0; row < 6; row++)
4464 {
4465 ImGui::TableNextRow();
4466 for (int column = 0; column < 3; column++)
4467 {
4468 ImGui::TableSetColumnIndex(column_n: column);
4469 ImGui::Text(fmt: "Fixed %d,%d", column, row);
4470 }
4471 }
4472 ImGui::EndTable();
4473 }
4474 ImGui::TreePop();
4475 }
4476
4477 if (open_action != -1)
4478 ImGui::SetNextItemOpen(is_open: open_action != 0);
4479 IMGUI_DEMO_MARKER("Tables/Padding");
4480 if (ImGui::TreeNode(label: "Padding"))
4481 {
4482 // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
4483 // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
4484 HelpMarker(
4485 desc: "We often want outer padding activated when any using features which makes the edges of a column visible:\n"
4486 "e.g.:\n"
4487 "- BorderOuterV\n"
4488 "- any form of row selection\n"
4489 "Because of this, activating BorderOuterV sets the default to PadOuterX. "
4490 "Using PadOuterX or NoPadOuterX you can override the default.\n\n"
4491 "Actual padding values are using style.CellPadding.\n\n"
4492 "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
4493
4494 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
4495 PushStyleCompact();
4496 ImGui::CheckboxFlags(label: "ImGuiTableFlags_PadOuterX", flags: &flags1, flags_value: ImGuiTableFlags_PadOuterX);
4497 ImGui::SameLine(); HelpMarker(desc: "Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
4498 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoPadOuterX", flags: &flags1, flags_value: ImGuiTableFlags_NoPadOuterX);
4499 ImGui::SameLine(); HelpMarker(desc: "Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
4500 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoPadInnerX", flags: &flags1, flags_value: ImGuiTableFlags_NoPadInnerX);
4501 ImGui::SameLine(); HelpMarker(desc: "Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
4502 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuterV", flags: &flags1, flags_value: ImGuiTableFlags_BordersOuterV);
4503 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInnerV", flags: &flags1, flags_value: ImGuiTableFlags_BordersInnerV);
4504 static bool show_headers = false;
4505 ImGui::Checkbox(label: "show_headers", v: &show_headers);
4506 PopStyleCompact();
4507
4508 if (ImGui::BeginTable(str_id: "table_padding", column: 3, flags: flags1))
4509 {
4510 if (show_headers)
4511 {
4512 ImGui::TableSetupColumn(label: "One");
4513 ImGui::TableSetupColumn(label: "Two");
4514 ImGui::TableSetupColumn(label: "Three");
4515 ImGui::TableHeadersRow();
4516 }
4517
4518 for (int row = 0; row < 5; row++)
4519 {
4520 ImGui::TableNextRow();
4521 for (int column = 0; column < 3; column++)
4522 {
4523 ImGui::TableSetColumnIndex(column_n: column);
4524 if (row == 0)
4525 {
4526 ImGui::Text(fmt: "Avail %.2f", ImGui::GetContentRegionAvail().x);
4527 }
4528 else
4529 {
4530 char buf[32];
4531 sprintf(s: buf, format: "Hello %d,%d", column, row);
4532 ImGui::Button(label: buf, size: ImVec2(-FLT_MIN, 0.0f));
4533 }
4534 //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
4535 // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
4536 }
4537 }
4538 ImGui::EndTable();
4539 }
4540
4541 // Second example: set style.CellPadding to (0.0) or a custom value.
4542 // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
4543 HelpMarker(desc: "Setting style.CellPadding to (0,0) or a custom value.");
4544 static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
4545 static ImVec2 cell_padding(0.0f, 0.0f);
4546 static bool show_widget_frame_bg = true;
4547
4548 PushStyleCompact();
4549 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Borders", flags: &flags2, flags_value: ImGuiTableFlags_Borders);
4550 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersH", flags: &flags2, flags_value: ImGuiTableFlags_BordersH);
4551 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersV", flags: &flags2, flags_value: ImGuiTableFlags_BordersV);
4552 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInner", flags: &flags2, flags_value: ImGuiTableFlags_BordersInner);
4553 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuter", flags: &flags2, flags_value: ImGuiTableFlags_BordersOuter);
4554 ImGui::CheckboxFlags(label: "ImGuiTableFlags_RowBg", flags: &flags2, flags_value: ImGuiTableFlags_RowBg);
4555 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags2, flags_value: ImGuiTableFlags_Resizable);
4556 ImGui::Checkbox(label: "show_widget_frame_bg", v: &show_widget_frame_bg);
4557 ImGui::SliderFloat2(label: "CellPadding", v: &cell_padding.x, v_min: 0.0f, v_max: 10.0f, format: "%.0f");
4558 PopStyleCompact();
4559
4560 ImGui::PushStyleVar(idx: ImGuiStyleVar_CellPadding, val: cell_padding);
4561 if (ImGui::BeginTable(str_id: "table_padding_2", column: 3, flags: flags2))
4562 {
4563 static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
4564 static bool init = true;
4565 if (!show_widget_frame_bg)
4566 ImGui::PushStyleColor(idx: ImGuiCol_FrameBg, col: 0);
4567 for (int cell = 0; cell < 3 * 5; cell++)
4568 {
4569 ImGui::TableNextColumn();
4570 if (init)
4571 strcpy(dest: text_bufs[cell], src: "edit me");
4572 ImGui::SetNextItemWidth(-FLT_MIN);
4573 ImGui::PushID(int_id: cell);
4574 ImGui::InputText(label: "##cell", buf: text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
4575 ImGui::PopID();
4576 }
4577 if (!show_widget_frame_bg)
4578 ImGui::PopStyleColor();
4579 init = false;
4580 ImGui::EndTable();
4581 }
4582 ImGui::PopStyleVar();
4583
4584 ImGui::TreePop();
4585 }
4586
4587 if (open_action != -1)
4588 ImGui::SetNextItemOpen(is_open: open_action != 0);
4589 IMGUI_DEMO_MARKER("Tables/Explicit widths");
4590 if (ImGui::TreeNode(label: "Sizing policies"))
4591 {
4592 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
4593 PushStyleCompact();
4594 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags1, flags_value: ImGuiTableFlags_Resizable);
4595 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoHostExtendX", flags: &flags1, flags_value: ImGuiTableFlags_NoHostExtendX);
4596 PopStyleCompact();
4597
4598 static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
4599 for (int table_n = 0; table_n < 4; table_n++)
4600 {
4601 ImGui::PushID(int_id: table_n);
4602 ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
4603 EditTableSizingFlags(p_flags: &sizing_policy_flags[table_n]);
4604
4605 // To make it easier to understand the different sizing policy,
4606 // For each policy: we display one table where the columns have equal contents width,
4607 // and one where the columns have different contents width.
4608 if (ImGui::BeginTable(str_id: "table1", column: 3, flags: sizing_policy_flags[table_n] | flags1))
4609 {
4610 for (int row = 0; row < 3; row++)
4611 {
4612 ImGui::TableNextRow();
4613 ImGui::TableNextColumn(); ImGui::Text(fmt: "Oh dear");
4614 ImGui::TableNextColumn(); ImGui::Text(fmt: "Oh dear");
4615 ImGui::TableNextColumn(); ImGui::Text(fmt: "Oh dear");
4616 }
4617 ImGui::EndTable();
4618 }
4619 if (ImGui::BeginTable(str_id: "table2", column: 3, flags: sizing_policy_flags[table_n] | flags1))
4620 {
4621 for (int row = 0; row < 3; row++)
4622 {
4623 ImGui::TableNextRow();
4624 ImGui::TableNextColumn(); ImGui::Text(fmt: "AAAA");
4625 ImGui::TableNextColumn(); ImGui::Text(fmt: "BBBBBBBB");
4626 ImGui::TableNextColumn(); ImGui::Text(fmt: "CCCCCCCCCCCC");
4627 }
4628 ImGui::EndTable();
4629 }
4630 ImGui::PopID();
4631 }
4632
4633 ImGui::Spacing();
4634 ImGui::TextUnformatted(text: "Advanced");
4635 ImGui::SameLine();
4636 HelpMarker(
4637 desc: "This section allows you to interact and see the effect of various sizing policies "
4638 "depending on whether Scroll is enabled and the contents of your columns.");
4639
4640 enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
4641 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
4642 static int contents_type = CT_ShowWidth;
4643 static int column_count = 3;
4644
4645 PushStyleCompact();
4646 ImGui::PushID(str_id: "Advanced");
4647 ImGui::PushItemWidth(item_width: TEXT_BASE_WIDTH * 30);
4648 EditTableSizingFlags(p_flags: &flags);
4649 ImGui::Combo(label: "Contents", current_item: &contents_type, items_separated_by_zeros: "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
4650 if (contents_type == CT_FillButton)
4651 {
4652 ImGui::SameLine();
4653 HelpMarker(
4654 desc: "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
4655 "where contents width can feed into auto-column width can feed into contents width.");
4656 }
4657 ImGui::DragInt(label: "Columns", v: &column_count, v_speed: 0.1f, v_min: 1, v_max: 64, format: "%d", flags: ImGuiSliderFlags_AlwaysClamp);
4658 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags, flags_value: ImGuiTableFlags_Resizable);
4659 ImGui::CheckboxFlags(label: "ImGuiTableFlags_PreciseWidths", flags: &flags, flags_value: ImGuiTableFlags_PreciseWidths);
4660 ImGui::SameLine(); HelpMarker(desc: "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.");
4661 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollX", flags: &flags, flags_value: ImGuiTableFlags_ScrollX);
4662 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollY", flags: &flags, flags_value: ImGuiTableFlags_ScrollY);
4663 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoClip", flags: &flags, flags_value: ImGuiTableFlags_NoClip);
4664 ImGui::PopItemWidth();
4665 ImGui::PopID();
4666 PopStyleCompact();
4667
4668 if (ImGui::BeginTable(str_id: "table2", column: column_count, flags, outer_size: ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
4669 {
4670 for (int cell = 0; cell < 10 * column_count; cell++)
4671 {
4672 ImGui::TableNextColumn();
4673 int column = ImGui::TableGetColumnIndex();
4674 int row = ImGui::TableGetRowIndex();
4675
4676 ImGui::PushID(int_id: cell);
4677 char label[32];
4678 static char text_buf[32] = "";
4679 sprintf(s: label, format: "Hello %d,%d", column, row);
4680 switch (contents_type)
4681 {
4682 case CT_ShortText: ImGui::TextUnformatted(text: label); break;
4683 case CT_LongText: ImGui::Text(fmt: "Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
4684 case CT_ShowWidth: ImGui::Text(fmt: "W: %.1f", ImGui::GetContentRegionAvail().x); break;
4685 case CT_Button: ImGui::Button(label); break;
4686 case CT_FillButton: ImGui::Button(label, size: ImVec2(-FLT_MIN, 0.0f)); break;
4687 case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText(label: "##", buf: text_buf, IM_ARRAYSIZE(text_buf)); break;
4688 }
4689 ImGui::PopID();
4690 }
4691 ImGui::EndTable();
4692 }
4693 ImGui::TreePop();
4694 }
4695
4696 if (open_action != -1)
4697 ImGui::SetNextItemOpen(is_open: open_action != 0);
4698 IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
4699 if (ImGui::TreeNode(label: "Vertical scrolling, with clipping"))
4700 {
4701 HelpMarker(
4702 desc: "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
4703 "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
4704 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4705
4706 PushStyleCompact();
4707 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollY", flags: &flags, flags_value: ImGuiTableFlags_ScrollY);
4708 PopStyleCompact();
4709
4710 // When using ScrollX or ScrollY we need to specify a size for our table container!
4711 // Otherwise by default the table will fit all available space, like a BeginChild() call.
4712 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
4713 if (ImGui::BeginTable(str_id: "table_scrolly", column: 3, flags, outer_size))
4714 {
4715 ImGui::TableSetupScrollFreeze(cols: 0, rows: 1); // Make top row always visible
4716 ImGui::TableSetupColumn(label: "One", flags: ImGuiTableColumnFlags_None);
4717 ImGui::TableSetupColumn(label: "Two", flags: ImGuiTableColumnFlags_None);
4718 ImGui::TableSetupColumn(label: "Three", flags: ImGuiTableColumnFlags_None);
4719 ImGui::TableHeadersRow();
4720
4721 // Demonstrate using clipper for large vertical lists
4722 ImGuiListClipper clipper;
4723 clipper.Begin(items_count: 1000);
4724 while (clipper.Step())
4725 {
4726 for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
4727 {
4728 ImGui::TableNextRow();
4729 for (int column = 0; column < 3; column++)
4730 {
4731 ImGui::TableSetColumnIndex(column_n: column);
4732 ImGui::Text(fmt: "Hello %d,%d", column, row);
4733 }
4734 }
4735 }
4736 ImGui::EndTable();
4737 }
4738 ImGui::TreePop();
4739 }
4740
4741 if (open_action != -1)
4742 ImGui::SetNextItemOpen(is_open: open_action != 0);
4743 IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
4744 if (ImGui::TreeNode(label: "Horizontal scrolling"))
4745 {
4746 HelpMarker(
4747 desc: "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
4748 "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
4749 "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
4750 "because the container window won't automatically extend vertically to fix contents "
4751 "(this may be improved in future versions).");
4752 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4753 static int freeze_cols = 1;
4754 static int freeze_rows = 1;
4755
4756 PushStyleCompact();
4757 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags, flags_value: ImGuiTableFlags_Resizable);
4758 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollX", flags: &flags, flags_value: ImGuiTableFlags_ScrollX);
4759 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollY", flags: &flags, flags_value: ImGuiTableFlags_ScrollY);
4760 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
4761 ImGui::DragInt(label: "freeze_cols", v: &freeze_cols, v_speed: 0.2f, v_min: 0, v_max: 9, NULL, flags: ImGuiSliderFlags_NoInput);
4762 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
4763 ImGui::DragInt(label: "freeze_rows", v: &freeze_rows, v_speed: 0.2f, v_min: 0, v_max: 9, NULL, flags: ImGuiSliderFlags_NoInput);
4764 PopStyleCompact();
4765
4766 // When using ScrollX or ScrollY we need to specify a size for our table container!
4767 // Otherwise by default the table will fit all available space, like a BeginChild() call.
4768 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
4769 if (ImGui::BeginTable(str_id: "table_scrollx", column: 7, flags, outer_size))
4770 {
4771 ImGui::TableSetupScrollFreeze(cols: freeze_cols, rows: freeze_rows);
4772 ImGui::TableSetupColumn(label: "Line #", flags: ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
4773 ImGui::TableSetupColumn(label: "One");
4774 ImGui::TableSetupColumn(label: "Two");
4775 ImGui::TableSetupColumn(label: "Three");
4776 ImGui::TableSetupColumn(label: "Four");
4777 ImGui::TableSetupColumn(label: "Five");
4778 ImGui::TableSetupColumn(label: "Six");
4779 ImGui::TableHeadersRow();
4780 for (int row = 0; row < 20; row++)
4781 {
4782 ImGui::TableNextRow();
4783 for (int column = 0; column < 7; column++)
4784 {
4785 // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
4786 // Because here we know that:
4787 // - A) all our columns are contributing the same to row height
4788 // - B) column 0 is always visible,
4789 // We only always submit this one column and can skip others.
4790 // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
4791 if (!ImGui::TableSetColumnIndex(column_n: column) && column > 0)
4792 continue;
4793 if (column == 0)
4794 ImGui::Text(fmt: "Line %d", row);
4795 else
4796 ImGui::Text(fmt: "Hello world %d,%d", column, row);
4797 }
4798 }
4799 ImGui::EndTable();
4800 }
4801
4802 ImGui::Spacing();
4803 ImGui::TextUnformatted(text: "Stretch + ScrollX");
4804 ImGui::SameLine();
4805 HelpMarker(
4806 desc: "Showcase using Stretch columns + ScrollX together: "
4807 "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
4808 "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
4809 "along with ScrollX doesn't make sense.");
4810 static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
4811 static float inner_width = 1000.0f;
4812 PushStyleCompact();
4813 ImGui::PushID(str_id: "flags3");
4814 ImGui::PushItemWidth(item_width: TEXT_BASE_WIDTH * 30);
4815 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollX", flags: &flags2, flags_value: ImGuiTableFlags_ScrollX);
4816 ImGui::DragFloat(label: "inner_width", v: &inner_width, v_speed: 1.0f, v_min: 0.0f, FLT_MAX, format: "%.1f");
4817 ImGui::PopItemWidth();
4818 ImGui::PopID();
4819 PopStyleCompact();
4820 if (ImGui::BeginTable(str_id: "table2", column: 7, flags: flags2, outer_size, inner_width))
4821 {
4822 for (int cell = 0; cell < 20 * 7; cell++)
4823 {
4824 ImGui::TableNextColumn();
4825 ImGui::Text(fmt: "Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
4826 }
4827 ImGui::EndTable();
4828 }
4829 ImGui::TreePop();
4830 }
4831
4832 if (open_action != -1)
4833 ImGui::SetNextItemOpen(is_open: open_action != 0);
4834 IMGUI_DEMO_MARKER("Tables/Columns flags");
4835 if (ImGui::TreeNode(label: "Columns flags"))
4836 {
4837 // Create a first table just to show all the options/flags we want to make visible in our example!
4838 const int column_count = 3;
4839 const char* column_names[column_count] = { "One", "Two", "Three" };
4840 static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
4841 static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
4842
4843 if (ImGui::BeginTable(str_id: "table_columns_flags_checkboxes", column: column_count, flags: ImGuiTableFlags_None))
4844 {
4845 PushStyleCompact();
4846 for (int column = 0; column < column_count; column++)
4847 {
4848 ImGui::TableNextColumn();
4849 ImGui::PushID(int_id: column);
4850 ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
4851 ImGui::Text(fmt: "'%s'", column_names[column]);
4852 ImGui::Spacing();
4853 ImGui::Text(fmt: "Input flags:");
4854 EditTableColumnsFlags(p_flags: &column_flags[column]);
4855 ImGui::Spacing();
4856 ImGui::Text(fmt: "Output flags:");
4857 ImGui::BeginDisabled();
4858 ShowTableColumnsStatusFlags(flags: column_flags_out[column]);
4859 ImGui::EndDisabled();
4860 ImGui::PopID();
4861 }
4862 PopStyleCompact();
4863 ImGui::EndTable();
4864 }
4865
4866 // Create the real table we care about for the example!
4867 // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
4868 // otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
4869 // + resizing the parent window down).
4870 const ImGuiTableFlags flags
4871 = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
4872 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
4873 | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
4874 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
4875 if (ImGui::BeginTable(str_id: "table_columns_flags", column: column_count, flags, outer_size))
4876 {
4877 bool has_angled_header = false;
4878 for (int column = 0; column < column_count; column++)
4879 {
4880 has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
4881 ImGui::TableSetupColumn(label: column_names[column], flags: column_flags[column]);
4882 }
4883 if (has_angled_header)
4884 ImGui::TableAngledHeadersRow();
4885 ImGui::TableHeadersRow();
4886 for (int column = 0; column < column_count; column++)
4887 column_flags_out[column] = ImGui::TableGetColumnFlags(column_n: column);
4888 float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
4889 for (int row = 0; row < 8; row++)
4890 {
4891 // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
4892 ImGui::Indent(indent_w: indent_step);
4893 ImGui::TableNextRow();
4894 for (int column = 0; column < column_count; column++)
4895 {
4896 ImGui::TableSetColumnIndex(column_n: column);
4897 ImGui::Text(fmt: "%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column_n: column));
4898 }
4899 }
4900 ImGui::Unindent(indent_w: indent_step * 8.0f);
4901
4902 ImGui::EndTable();
4903 }
4904 ImGui::TreePop();
4905 }
4906
4907 if (open_action != -1)
4908 ImGui::SetNextItemOpen(is_open: open_action != 0);
4909 IMGUI_DEMO_MARKER("Tables/Columns widths");
4910 if (ImGui::TreeNode(label: "Columns widths"))
4911 {
4912 HelpMarker(desc: "Using TableSetupColumn() to setup default width.");
4913
4914 static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
4915 PushStyleCompact();
4916 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags1, flags_value: ImGuiTableFlags_Resizable);
4917 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoBordersInBodyUntilResize", flags: &flags1, flags_value: ImGuiTableFlags_NoBordersInBodyUntilResize);
4918 PopStyleCompact();
4919 if (ImGui::BeginTable(str_id: "table1", column: 3, flags: flags1))
4920 {
4921 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
4922 ImGui::TableSetupColumn(label: "one", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 100.0f); // Default to 100.0f
4923 ImGui::TableSetupColumn(label: "two", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 200.0f); // Default to 200.0f
4924 ImGui::TableSetupColumn(label: "three", flags: ImGuiTableColumnFlags_WidthFixed); // Default to auto
4925 ImGui::TableHeadersRow();
4926 for (int row = 0; row < 4; row++)
4927 {
4928 ImGui::TableNextRow();
4929 for (int column = 0; column < 3; column++)
4930 {
4931 ImGui::TableSetColumnIndex(column_n: column);
4932 if (row == 0)
4933 ImGui::Text(fmt: "(w: %5.1f)", ImGui::GetContentRegionAvail().x);
4934 else
4935 ImGui::Text(fmt: "Hello %d,%d", column, row);
4936 }
4937 }
4938 ImGui::EndTable();
4939 }
4940
4941 HelpMarker(
4942 desc: "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
4943 "fixed columns with set width may still be shrunk down if there's not enough space in the host.");
4944
4945 static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
4946 PushStyleCompact();
4947 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoKeepColumnsVisible", flags: &flags2, flags_value: ImGuiTableFlags_NoKeepColumnsVisible);
4948 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInnerV", flags: &flags2, flags_value: ImGuiTableFlags_BordersInnerV);
4949 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuterV", flags: &flags2, flags_value: ImGuiTableFlags_BordersOuterV);
4950 PopStyleCompact();
4951 if (ImGui::BeginTable(str_id: "table2", column: 4, flags: flags2))
4952 {
4953 // We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
4954 // will default to ImGuiTableColumnFlags_WidthFixed.
4955 ImGui::TableSetupColumn(label: "", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 100.0f);
4956 ImGui::TableSetupColumn(label: "", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: TEXT_BASE_WIDTH * 15.0f);
4957 ImGui::TableSetupColumn(label: "", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: TEXT_BASE_WIDTH * 30.0f);
4958 ImGui::TableSetupColumn(label: "", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: TEXT_BASE_WIDTH * 15.0f);
4959 for (int row = 0; row < 5; row++)
4960 {
4961 ImGui::TableNextRow();
4962 for (int column = 0; column < 4; column++)
4963 {
4964 ImGui::TableSetColumnIndex(column_n: column);
4965 if (row == 0)
4966 ImGui::Text(fmt: "(w: %5.1f)", ImGui::GetContentRegionAvail().x);
4967 else
4968 ImGui::Text(fmt: "Hello %d,%d", column, row);
4969 }
4970 }
4971 ImGui::EndTable();
4972 }
4973 ImGui::TreePop();
4974 }
4975
4976 if (open_action != -1)
4977 ImGui::SetNextItemOpen(is_open: open_action != 0);
4978 IMGUI_DEMO_MARKER("Tables/Nested tables");
4979 if (ImGui::TreeNode(label: "Nested tables"))
4980 {
4981 HelpMarker(desc: "This demonstrates embedding a table into another table cell.");
4982
4983 if (ImGui::BeginTable(str_id: "table_nested1", column: 2, flags: ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
4984 {
4985 ImGui::TableSetupColumn(label: "A0");
4986 ImGui::TableSetupColumn(label: "A1");
4987 ImGui::TableHeadersRow();
4988
4989 ImGui::TableNextColumn();
4990 ImGui::Text(fmt: "A0 Row 0");
4991 {
4992 float rows_height = TEXT_BASE_HEIGHT * 2;
4993 if (ImGui::BeginTable(str_id: "table_nested2", column: 2, flags: ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
4994 {
4995 ImGui::TableSetupColumn(label: "B0");
4996 ImGui::TableSetupColumn(label: "B1");
4997 ImGui::TableHeadersRow();
4998
4999 ImGui::TableNextRow(row_flags: ImGuiTableRowFlags_None, min_row_height: rows_height);
5000 ImGui::TableNextColumn();
5001 ImGui::Text(fmt: "B0 Row 0");
5002 ImGui::TableNextColumn();
5003 ImGui::Text(fmt: "B1 Row 0");
5004 ImGui::TableNextRow(row_flags: ImGuiTableRowFlags_None, min_row_height: rows_height);
5005 ImGui::TableNextColumn();
5006 ImGui::Text(fmt: "B0 Row 1");
5007 ImGui::TableNextColumn();
5008 ImGui::Text(fmt: "B1 Row 1");
5009
5010 ImGui::EndTable();
5011 }
5012 }
5013 ImGui::TableNextColumn(); ImGui::Text(fmt: "A1 Row 0");
5014 ImGui::TableNextColumn(); ImGui::Text(fmt: "A0 Row 1");
5015 ImGui::TableNextColumn(); ImGui::Text(fmt: "A1 Row 1");
5016 ImGui::EndTable();
5017 }
5018 ImGui::TreePop();
5019 }
5020
5021 if (open_action != -1)
5022 ImGui::SetNextItemOpen(is_open: open_action != 0);
5023 IMGUI_DEMO_MARKER("Tables/Row height");
5024 if (ImGui::TreeNode(label: "Row height"))
5025 {
5026 HelpMarker(
5027 desc: "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
5028 "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
5029 "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
5030 if (ImGui::BeginTable(str_id: "table_row_height", column: 1, flags: ImGuiTableFlags_Borders))
5031 {
5032 for (int row = 0; row < 8; row++)
5033 {
5034 float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
5035 ImGui::TableNextRow(row_flags: ImGuiTableRowFlags_None, min_row_height);
5036 ImGui::TableNextColumn();
5037 ImGui::Text(fmt: "min_row_height = %.2f", min_row_height);
5038 }
5039 ImGui::EndTable();
5040 }
5041
5042 HelpMarker(
5043 desc: "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
5044 "Please note that Tables Row Height is not the same thing as Current Line Height, "
5045 "as a table cell may contains multiple lines.");
5046 if (ImGui::BeginTable(str_id: "table_share_lineheight", column: 2, flags: ImGuiTableFlags_Borders))
5047 {
5048 ImGui::TableNextRow();
5049 ImGui::TableNextColumn();
5050 ImGui::ColorButton(desc_id: "##1", col: ImVec4(0.13f, 0.26f, 0.40f, 1.0f), flags: ImGuiColorEditFlags_None, size: ImVec2(40, 40));
5051 ImGui::TableNextColumn();
5052 ImGui::Text(fmt: "Line 1");
5053 ImGui::Text(fmt: "Line 2");
5054
5055 ImGui::TableNextRow();
5056 ImGui::TableNextColumn();
5057 ImGui::ColorButton(desc_id: "##2", col: ImVec4(0.13f, 0.26f, 0.40f, 1.0f), flags: ImGuiColorEditFlags_None, size: ImVec2(40, 40));
5058 ImGui::TableNextColumn();
5059 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: 0.0f); // Reuse line height from previous column
5060 ImGui::Text(fmt: "Line 1, with SameLine(0,0)");
5061 ImGui::Text(fmt: "Line 2");
5062
5063 ImGui::EndTable();
5064 }
5065
5066 HelpMarker(desc: "Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
5067 if (ImGui::BeginTable(str_id: "table_changing_cellpadding_y", column: 1, flags: ImGuiTableFlags_Borders))
5068 {
5069 ImGuiStyle& style = ImGui::GetStyle();
5070 for (int row = 0; row < 8; row++)
5071 {
5072 if ((row % 3) == 2)
5073 ImGui::PushStyleVar(idx: ImGuiStyleVar_CellPadding, val: ImVec2(style.CellPadding.x, 20.0f));
5074 ImGui::TableNextRow(row_flags: ImGuiTableRowFlags_None);
5075 ImGui::TableNextColumn();
5076 ImGui::Text(fmt: "CellPadding.y = %.2f", style.CellPadding.y);
5077 if ((row % 3) == 2)
5078 ImGui::PopStyleVar();
5079 }
5080 ImGui::EndTable();
5081 }
5082
5083 ImGui::TreePop();
5084 }
5085
5086 if (open_action != -1)
5087 ImGui::SetNextItemOpen(is_open: open_action != 0);
5088 IMGUI_DEMO_MARKER("Tables/Outer size");
5089 if (ImGui::TreeNode(label: "Outer size"))
5090 {
5091 // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
5092 // Important to that note how the two flags have slightly different behaviors!
5093 ImGui::Text(fmt: "Using NoHostExtendX and NoHostExtendY:");
5094 PushStyleCompact();
5095 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
5096 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoHostExtendX", flags: &flags, flags_value: ImGuiTableFlags_NoHostExtendX);
5097 ImGui::SameLine(); HelpMarker(desc: "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.");
5098 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoHostExtendY", flags: &flags, flags_value: ImGuiTableFlags_NoHostExtendY);
5099 ImGui::SameLine(); HelpMarker(desc: "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.");
5100 PopStyleCompact();
5101
5102 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
5103 if (ImGui::BeginTable(str_id: "table1", column: 3, flags, outer_size))
5104 {
5105 for (int row = 0; row < 10; row++)
5106 {
5107 ImGui::TableNextRow();
5108 for (int column = 0; column < 3; column++)
5109 {
5110 ImGui::TableNextColumn();
5111 ImGui::Text(fmt: "Cell %d,%d", column, row);
5112 }
5113 }
5114 ImGui::EndTable();
5115 }
5116 ImGui::SameLine();
5117 ImGui::Text(fmt: "Hello!");
5118
5119 ImGui::Spacing();
5120
5121 ImGui::Text(fmt: "Using explicit size:");
5122 if (ImGui::BeginTable(str_id: "table2", column: 3, flags: ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, outer_size: ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
5123 {
5124 for (int row = 0; row < 5; row++)
5125 {
5126 ImGui::TableNextRow();
5127 for (int column = 0; column < 3; column++)
5128 {
5129 ImGui::TableNextColumn();
5130 ImGui::Text(fmt: "Cell %d,%d", column, row);
5131 }
5132 }
5133 ImGui::EndTable();
5134 }
5135 ImGui::SameLine();
5136 if (ImGui::BeginTable(str_id: "table3", column: 3, flags: ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, outer_size: ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
5137 {
5138 for (int row = 0; row < 3; row++)
5139 {
5140 ImGui::TableNextRow(row_flags: 0, min_row_height: TEXT_BASE_HEIGHT * 1.5f);
5141 for (int column = 0; column < 3; column++)
5142 {
5143 ImGui::TableNextColumn();
5144 ImGui::Text(fmt: "Cell %d,%d", column, row);
5145 }
5146 }
5147 ImGui::EndTable();
5148 }
5149
5150 ImGui::TreePop();
5151 }
5152
5153 if (open_action != -1)
5154 ImGui::SetNextItemOpen(is_open: open_action != 0);
5155 IMGUI_DEMO_MARKER("Tables/Background color");
5156 if (ImGui::TreeNode(label: "Background color"))
5157 {
5158 static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
5159 static int row_bg_type = 1;
5160 static int row_bg_target = 1;
5161 static int cell_bg_type = 1;
5162
5163 PushStyleCompact();
5164 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Borders", flags: &flags, flags_value: ImGuiTableFlags_Borders);
5165 ImGui::CheckboxFlags(label: "ImGuiTableFlags_RowBg", flags: &flags, flags_value: ImGuiTableFlags_RowBg);
5166 ImGui::SameLine(); HelpMarker(desc: "ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
5167 ImGui::Combo(label: "row bg type", current_item: (int*)&row_bg_type, items_separated_by_zeros: "None\0Red\0Gradient\0");
5168 ImGui::Combo(label: "row bg target", current_item: (int*)&row_bg_target, items_separated_by_zeros: "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker(desc: "Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.");
5169 ImGui::Combo(label: "cell bg type", current_item: (int*)&cell_bg_type, items_separated_by_zeros: "None\0Blue\0"); ImGui::SameLine(); HelpMarker(desc: "We are colorizing cells to B1->C2 here.");
5170 IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
5171 IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
5172 IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
5173 PopStyleCompact();
5174
5175 if (ImGui::BeginTable(str_id: "table1", column: 5, flags))
5176 {
5177 for (int row = 0; row < 6; row++)
5178 {
5179 ImGui::TableNextRow();
5180
5181 // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
5182 // 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.
5183 if (row_bg_type != 0)
5184 {
5185 ImU32 row_bg_color = ImGui::GetColorU32(col: 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?
5186 ImGui::TableSetBgColor(target: ImGuiTableBgTarget_RowBg0 + row_bg_target, color: row_bg_color);
5187 }
5188
5189 // Fill cells
5190 for (int column = 0; column < 5; column++)
5191 {
5192 ImGui::TableSetColumnIndex(column_n: column);
5193 ImGui::Text(fmt: "%c%c", 'A' + row, '0' + column);
5194
5195 // Change background of Cells B1->C2
5196 // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
5197 // (the CellBg color will be blended over the RowBg and ColumnBg colors)
5198 // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
5199 if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
5200 {
5201 ImU32 cell_bg_color = ImGui::GetColorU32(col: ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
5202 ImGui::TableSetBgColor(target: ImGuiTableBgTarget_CellBg, color: cell_bg_color);
5203 }
5204 }
5205 }
5206 ImGui::EndTable();
5207 }
5208 ImGui::TreePop();
5209 }
5210
5211 if (open_action != -1)
5212 ImGui::SetNextItemOpen(is_open: open_action != 0);
5213 IMGUI_DEMO_MARKER("Tables/Tree view");
5214 if (ImGui::TreeNode(label: "Tree view"))
5215 {
5216 static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
5217
5218 static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
5219 ImGui::CheckboxFlags(label: "ImGuiTreeNodeFlags_SpanFullWidth", flags: &tree_node_flags, flags_value: ImGuiTreeNodeFlags_SpanFullWidth);
5220 ImGui::CheckboxFlags(label: "ImGuiTreeNodeFlags_SpanAllColumns", flags: &tree_node_flags, flags_value: ImGuiTreeNodeFlags_SpanAllColumns);
5221
5222 HelpMarker(desc: "See \"Columns flags\" section to configure how indentation is applied to individual columns.");
5223 if (ImGui::BeginTable(str_id: "3ways", column: 3, flags))
5224 {
5225 // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
5226 ImGui::TableSetupColumn(label: "Name", flags: ImGuiTableColumnFlags_NoHide);
5227 ImGui::TableSetupColumn(label: "Size", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: TEXT_BASE_WIDTH * 12.0f);
5228 ImGui::TableSetupColumn(label: "Type", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: TEXT_BASE_WIDTH * 18.0f);
5229 ImGui::TableHeadersRow();
5230
5231 // Simple storage to output a dummy file-system.
5232 struct MyTreeNode
5233 {
5234 const char* Name;
5235 const char* Type;
5236 int Size;
5237 int ChildIdx;
5238 int ChildCount;
5239 static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
5240 {
5241 ImGui::TableNextRow();
5242 ImGui::TableNextColumn();
5243 const bool is_folder = (node->ChildCount > 0);
5244 if (is_folder)
5245 {
5246 bool open = ImGui::TreeNodeEx(label: node->Name, flags: tree_node_flags);
5247 ImGui::TableNextColumn();
5248 ImGui::TextDisabled(fmt: "--");
5249 ImGui::TableNextColumn();
5250 ImGui::TextUnformatted(text: node->Type);
5251 if (open)
5252 {
5253 for (int child_n = 0; child_n < node->ChildCount; child_n++)
5254 DisplayNode(node: &all_nodes[node->ChildIdx + child_n], all_nodes);
5255 ImGui::TreePop();
5256 }
5257 }
5258 else
5259 {
5260 ImGui::TreeNodeEx(label: node->Name, flags: tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
5261 ImGui::TableNextColumn();
5262 ImGui::Text(fmt: "%d", node->Size);
5263 ImGui::TableNextColumn();
5264 ImGui::TextUnformatted(text: node->Type);
5265 }
5266 }
5267 };
5268 static const MyTreeNode nodes[] =
5269 {
5270 { .Name: "Root", .Type: "Folder", .Size: -1, .ChildIdx: 1, .ChildCount: 3 }, // 0
5271 { .Name: "Music", .Type: "Folder", .Size: -1, .ChildIdx: 4, .ChildCount: 2 }, // 1
5272 { .Name: "Textures", .Type: "Folder", .Size: -1, .ChildIdx: 6, .ChildCount: 3 }, // 2
5273 { .Name: "desktop.ini", .Type: "System file", .Size: 1024, .ChildIdx: -1,.ChildCount: -1 }, // 3
5274 { .Name: "File1_a.wav", .Type: "Audio file", .Size: 123000, .ChildIdx: -1,.ChildCount: -1 }, // 4
5275 { .Name: "File1_b.wav", .Type: "Audio file", .Size: 456000, .ChildIdx: -1,.ChildCount: -1 }, // 5
5276 { .Name: "Image001.png", .Type: "Image file", .Size: 203128, .ChildIdx: -1,.ChildCount: -1 }, // 6
5277 { .Name: "Copy of Image001.png", .Type: "Image file", .Size: 203256, .ChildIdx: -1,.ChildCount: -1 }, // 7
5278 { .Name: "Copy of Image001 (Final2).png",.Type: "Image file", .Size: 203512, .ChildIdx: -1,.ChildCount: -1 }, // 8
5279 };
5280
5281 MyTreeNode::DisplayNode(node: &nodes[0], all_nodes: nodes);
5282
5283 ImGui::EndTable();
5284 }
5285 ImGui::TreePop();
5286 }
5287
5288 if (open_action != -1)
5289 ImGui::SetNextItemOpen(is_open: open_action != 0);
5290 IMGUI_DEMO_MARKER("Tables/Item width");
5291 if (ImGui::TreeNode(label: "Item width"))
5292 {
5293 HelpMarker(
5294 desc: "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
5295 "Note that on auto-resizing non-resizable fixed columns, querying the content width for "
5296 "e.g. right-alignment doesn't make sense.");
5297 if (ImGui::BeginTable(str_id: "table_item_width", column: 3, flags: ImGuiTableFlags_Borders))
5298 {
5299 ImGui::TableSetupColumn(label: "small");
5300 ImGui::TableSetupColumn(label: "half");
5301 ImGui::TableSetupColumn(label: "right-align");
5302 ImGui::TableHeadersRow();
5303
5304 for (int row = 0; row < 3; row++)
5305 {
5306 ImGui::TableNextRow();
5307 if (row == 0)
5308 {
5309 // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
5310 ImGui::TableSetColumnIndex(column_n: 0);
5311 ImGui::PushItemWidth(item_width: TEXT_BASE_WIDTH * 3.0f); // Small
5312 ImGui::TableSetColumnIndex(column_n: 1);
5313 ImGui::PushItemWidth(item_width: -ImGui::GetContentRegionAvail().x * 0.5f);
5314 ImGui::TableSetColumnIndex(column_n: 2);
5315 ImGui::PushItemWidth(item_width: -FLT_MIN); // Right-aligned
5316 }
5317
5318 // Draw our contents
5319 static float dummy_f = 0.0f;
5320 ImGui::PushID(int_id: row);
5321 ImGui::TableSetColumnIndex(column_n: 0);
5322 ImGui::SliderFloat(label: "float0", v: &dummy_f, v_min: 0.0f, v_max: 1.0f);
5323 ImGui::TableSetColumnIndex(column_n: 1);
5324 ImGui::SliderFloat(label: "float1", v: &dummy_f, v_min: 0.0f, v_max: 1.0f);
5325 ImGui::TableSetColumnIndex(column_n: 2);
5326 ImGui::SliderFloat(label: "##float2", v: &dummy_f, v_min: 0.0f, v_max: 1.0f); // No visible label since right-aligned
5327 ImGui::PopID();
5328 }
5329 ImGui::EndTable();
5330 }
5331 ImGui::TreePop();
5332 }
5333
5334 // Demonstrate using TableHeader() calls instead of TableHeadersRow()
5335 if (open_action != -1)
5336 ImGui::SetNextItemOpen(is_open: open_action != 0);
5337 IMGUI_DEMO_MARKER("Tables/Custom headers");
5338 if (ImGui::TreeNode(label: "Custom headers"))
5339 {
5340 const int COLUMNS_COUNT = 3;
5341 if (ImGui::BeginTable(str_id: "table_custom_headers", column: COLUMNS_COUNT, flags: ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
5342 {
5343 ImGui::TableSetupColumn(label: "Apricot");
5344 ImGui::TableSetupColumn(label: "Banana");
5345 ImGui::TableSetupColumn(label: "Cherry");
5346
5347 // Dummy entire-column selection storage
5348 // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
5349 static bool column_selected[3] = {};
5350
5351 // Instead of calling TableHeadersRow() we'll submit custom headers ourselves
5352 ImGui::TableNextRow(row_flags: ImGuiTableRowFlags_Headers);
5353 for (int column = 0; column < COLUMNS_COUNT; column++)
5354 {
5355 ImGui::TableSetColumnIndex(column_n: column);
5356 const char* column_name = ImGui::TableGetColumnName(column_n: column); // Retrieve name passed to TableSetupColumn()
5357 ImGui::PushID(int_id: column);
5358 ImGui::PushStyleVar(idx: ImGuiStyleVar_FramePadding, val: ImVec2(0, 0));
5359 ImGui::Checkbox(label: "##checkall", v: &column_selected[column]);
5360 ImGui::PopStyleVar();
5361 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: ImGui::GetStyle().ItemInnerSpacing.x);
5362 ImGui::TableHeader(label: column_name);
5363 ImGui::PopID();
5364 }
5365
5366 for (int row = 0; row < 5; row++)
5367 {
5368 ImGui::TableNextRow();
5369 for (int column = 0; column < 3; column++)
5370 {
5371 char buf[32];
5372 sprintf(s: buf, format: "Cell %d,%d", column, row);
5373 ImGui::TableSetColumnIndex(column_n: column);
5374 ImGui::Selectable(label: buf, selected: column_selected[column]);
5375 }
5376 }
5377 ImGui::EndTable();
5378 }
5379 ImGui::TreePop();
5380 }
5381
5382 // Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
5383 if (open_action != -1)
5384 ImGui::SetNextItemOpen(is_open: open_action != 0);
5385 IMGUI_DEMO_MARKER("Tables/Angled headers");
5386 if (ImGui::TreeNode(label: "Angled headers"))
5387 {
5388 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" };
5389 const int columns_count = IM_ARRAYSIZE(column_names);
5390 const int rows_count = 12;
5391
5392 static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
5393 static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
5394 static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
5395 static int frozen_cols = 1;
5396 static int frozen_rows = 2;
5397 ImGui::CheckboxFlags(label: "_ScrollX", flags: &table_flags, flags_value: ImGuiTableFlags_ScrollX);
5398 ImGui::CheckboxFlags(label: "_ScrollY", flags: &table_flags, flags_value: ImGuiTableFlags_ScrollY);
5399 ImGui::CheckboxFlags(label: "_Resizable", flags: &table_flags, flags_value: ImGuiTableFlags_Resizable);
5400 ImGui::CheckboxFlags(label: "_NoBordersInBody", flags: &table_flags, flags_value: ImGuiTableFlags_NoBordersInBody);
5401 ImGui::CheckboxFlags(label: "_HighlightHoveredColumn", flags: &table_flags, flags_value: ImGuiTableFlags_HighlightHoveredColumn);
5402 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
5403 ImGui::SliderInt(label: "Frozen columns", v: &frozen_cols, v_min: 0, v_max: 2);
5404 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
5405 ImGui::SliderInt(label: "Frozen rows", v: &frozen_rows, v_min: 0, v_max: 2);
5406 ImGui::CheckboxFlags(label: "Disable header contributing to column width", flags: &column_flags, flags_value: ImGuiTableColumnFlags_NoHeaderWidth);
5407
5408 if (ImGui::BeginTable(str_id: "table_angled_headers", column: columns_count, flags: table_flags, outer_size: ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
5409 {
5410 ImGui::TableSetupColumn(label: column_names[0], flags: ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
5411 for (int n = 1; n < columns_count; n++)
5412 ImGui::TableSetupColumn(label: column_names[n], flags: column_flags);
5413 ImGui::TableSetupScrollFreeze(cols: frozen_cols, rows: frozen_rows);
5414
5415 ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
5416 ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions.
5417 for (int row = 0; row < rows_count; row++)
5418 {
5419 ImGui::PushID(int_id: row);
5420 ImGui::TableNextRow();
5421 ImGui::TableSetColumnIndex(column_n: 0);
5422 ImGui::AlignTextToFramePadding();
5423 ImGui::Text(fmt: "Track %d", row);
5424 for (int column = 1; column < columns_count; column++)
5425 if (ImGui::TableSetColumnIndex(column_n: column))
5426 {
5427 ImGui::PushID(int_id: column);
5428 ImGui::Checkbox(label: "", v: &bools[row * columns_count + column]);
5429 ImGui::PopID();
5430 }
5431 ImGui::PopID();
5432 }
5433 ImGui::EndTable();
5434 }
5435 ImGui::TreePop();
5436 }
5437
5438 // Demonstrate creating custom context menus inside columns,
5439 // while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
5440 if (open_action != -1)
5441 ImGui::SetNextItemOpen(is_open: open_action != 0);
5442 IMGUI_DEMO_MARKER("Tables/Context menus");
5443 if (ImGui::TreeNode(label: "Context menus"))
5444 {
5445 HelpMarker(
5446 desc: "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
5447 "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
5448 static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
5449
5450 PushStyleCompact();
5451 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ContextMenuInBody", flags: &flags1, flags_value: ImGuiTableFlags_ContextMenuInBody);
5452 PopStyleCompact();
5453
5454 // Context Menus: first example
5455 // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
5456 // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
5457 const int COLUMNS_COUNT = 3;
5458 if (ImGui::BeginTable(str_id: "table_context_menu", column: COLUMNS_COUNT, flags: flags1))
5459 {
5460 ImGui::TableSetupColumn(label: "One");
5461 ImGui::TableSetupColumn(label: "Two");
5462 ImGui::TableSetupColumn(label: "Three");
5463
5464 // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
5465 ImGui::TableHeadersRow();
5466
5467 // Submit dummy contents
5468 for (int row = 0; row < 4; row++)
5469 {
5470 ImGui::TableNextRow();
5471 for (int column = 0; column < COLUMNS_COUNT; column++)
5472 {
5473 ImGui::TableSetColumnIndex(column_n: column);
5474 ImGui::Text(fmt: "Cell %d,%d", column, row);
5475 }
5476 }
5477 ImGui::EndTable();
5478 }
5479
5480 // Context Menus: second example
5481 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
5482 // [2.2] Right-click on the ".." to open a custom popup
5483 // [2.3] Right-click in columns to open another custom popup
5484 HelpMarker(
5485 desc: "Demonstrate mixing table context menu (over header), item context button (over button) "
5486 "and custom per-colunm context menu (over column body).");
5487 ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
5488 if (ImGui::BeginTable(str_id: "table_context_menu_2", column: COLUMNS_COUNT, flags: flags2))
5489 {
5490 ImGui::TableSetupColumn(label: "One");
5491 ImGui::TableSetupColumn(label: "Two");
5492 ImGui::TableSetupColumn(label: "Three");
5493
5494 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
5495 ImGui::TableHeadersRow();
5496 for (int row = 0; row < 4; row++)
5497 {
5498 ImGui::TableNextRow();
5499 for (int column = 0; column < COLUMNS_COUNT; column++)
5500 {
5501 // Submit dummy contents
5502 ImGui::TableSetColumnIndex(column_n: column);
5503 ImGui::Text(fmt: "Cell %d,%d", column, row);
5504 ImGui::SameLine();
5505
5506 // [2.2] Right-click on the ".." to open a custom popup
5507 ImGui::PushID(int_id: row * COLUMNS_COUNT + column);
5508 ImGui::SmallButton(label: "..");
5509 if (ImGui::BeginPopupContextItem())
5510 {
5511 ImGui::Text(fmt: "This is the popup for Button(\"..\") in Cell %d,%d", column, row);
5512 if (ImGui::Button(label: "Close"))
5513 ImGui::CloseCurrentPopup();
5514 ImGui::EndPopup();
5515 }
5516 ImGui::PopID();
5517 }
5518 }
5519
5520 // [2.3] Right-click anywhere in columns to open another custom popup
5521 // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
5522 // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
5523 int hovered_column = -1;
5524 for (int column = 0; column < COLUMNS_COUNT + 1; column++)
5525 {
5526 ImGui::PushID(int_id: column);
5527 if (ImGui::TableGetColumnFlags(column_n: column) & ImGuiTableColumnFlags_IsHovered)
5528 hovered_column = column;
5529 if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(button: 1))
5530 ImGui::OpenPopup(str_id: "MyPopup");
5531 if (ImGui::BeginPopup(str_id: "MyPopup"))
5532 {
5533 if (column == COLUMNS_COUNT)
5534 ImGui::Text(fmt: "This is a custom popup for unused space after the last column.");
5535 else
5536 ImGui::Text(fmt: "This is a custom popup for Column %d", column);
5537 if (ImGui::Button(label: "Close"))
5538 ImGui::CloseCurrentPopup();
5539 ImGui::EndPopup();
5540 }
5541 ImGui::PopID();
5542 }
5543
5544 ImGui::EndTable();
5545 ImGui::Text(fmt: "Hovered column: %d", hovered_column);
5546 }
5547 ImGui::TreePop();
5548 }
5549
5550 // Demonstrate creating multiple tables with the same ID
5551 if (open_action != -1)
5552 ImGui::SetNextItemOpen(is_open: open_action != 0);
5553 IMGUI_DEMO_MARKER("Tables/Synced instances");
5554 if (ImGui::TreeNode(label: "Synced instances"))
5555 {
5556 HelpMarker(desc: "Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
5557
5558 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
5559 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags, flags_value: ImGuiTableFlags_Resizable);
5560 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollY", flags: &flags, flags_value: ImGuiTableFlags_ScrollY);
5561 ImGui::CheckboxFlags(label: "ImGuiTableFlags_SizingFixedFit", flags: &flags, flags_value: ImGuiTableFlags_SizingFixedFit);
5562 ImGui::CheckboxFlags(label: "ImGuiTableFlags_HighlightHoveredColumn", flags: &flags, flags_value: ImGuiTableFlags_HighlightHoveredColumn);
5563 for (int n = 0; n < 3; n++)
5564 {
5565 char buf[32];
5566 sprintf(s: buf, format: "Synced Table %d", n);
5567 bool open = ImGui::CollapsingHeader(label: buf, flags: ImGuiTreeNodeFlags_DefaultOpen);
5568 if (open && ImGui::BeginTable(str_id: "Table", column: 3, flags, outer_size: ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
5569 {
5570 ImGui::TableSetupColumn(label: "One");
5571 ImGui::TableSetupColumn(label: "Two");
5572 ImGui::TableSetupColumn(label: "Three");
5573 ImGui::TableHeadersRow();
5574 const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
5575 for (int cell = 0; cell < cell_count; cell++)
5576 {
5577 ImGui::TableNextColumn();
5578 ImGui::Text(fmt: "this cell %d", cell);
5579 }
5580 ImGui::EndTable();
5581 }
5582 }
5583 ImGui::TreePop();
5584 }
5585
5586 // Demonstrate using Sorting facilities
5587 // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
5588 // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
5589 static const char* template_items_names[] =
5590 {
5591 "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
5592 "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
5593 };
5594 if (open_action != -1)
5595 ImGui::SetNextItemOpen(is_open: open_action != 0);
5596 IMGUI_DEMO_MARKER("Tables/Sorting");
5597 if (ImGui::TreeNode(label: "Sorting"))
5598 {
5599 // Create item list
5600 static ImVector<MyItem> items;
5601 if (items.Size == 0)
5602 {
5603 items.resize(new_size: 50, v: MyItem());
5604 for (int n = 0; n < items.Size; n++)
5605 {
5606 const int template_n = n % IM_ARRAYSIZE(template_items_names);
5607 MyItem& item = items[n];
5608 item.ID = n;
5609 item.Name = template_items_names[template_n];
5610 item.Quantity = (n * n - n) % 20; // Assign default quantities
5611 }
5612 }
5613
5614 // Options
5615 static ImGuiTableFlags flags =
5616 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
5617 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
5618 | ImGuiTableFlags_ScrollY;
5619 PushStyleCompact();
5620 ImGui::CheckboxFlags(label: "ImGuiTableFlags_SortMulti", flags: &flags, flags_value: ImGuiTableFlags_SortMulti);
5621 ImGui::SameLine(); HelpMarker(desc: "When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
5622 ImGui::CheckboxFlags(label: "ImGuiTableFlags_SortTristate", flags: &flags, flags_value: ImGuiTableFlags_SortTristate);
5623 ImGui::SameLine(); HelpMarker(desc: "When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
5624 PopStyleCompact();
5625
5626 if (ImGui::BeginTable(str_id: "table_sorting", column: 4, flags, outer_size: ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), inner_width: 0.0f))
5627 {
5628 // Declare columns
5629 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
5630 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
5631 // Demonstrate using a mixture of flags among available sort-related flags:
5632 // - ImGuiTableColumnFlags_DefaultSort
5633 // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
5634 // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
5635 ImGui::TableSetupColumn(label: "ID", flags: ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 0.0f, user_id: MyItemColumnID_ID);
5636 ImGui::TableSetupColumn(label: "Name", flags: ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 0.0f, user_id: MyItemColumnID_Name);
5637 ImGui::TableSetupColumn(label: "Action", flags: ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 0.0f, user_id: MyItemColumnID_Action);
5638 ImGui::TableSetupColumn(label: "Quantity", flags: ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, init_width_or_weight: 0.0f, user_id: MyItemColumnID_Quantity);
5639 ImGui::TableSetupScrollFreeze(cols: 0, rows: 1); // Make row always visible
5640 ImGui::TableHeadersRow();
5641
5642 // Sort our data if sort specs have been changed!
5643 if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
5644 if (sort_specs->SpecsDirty)
5645 {
5646 MyItem::SortWithSortSpecs(sort_specs, items: items.Data, items_count: items.Size);
5647 sort_specs->SpecsDirty = false;
5648 }
5649
5650 // Demonstrate using clipper for large vertical lists
5651 ImGuiListClipper clipper;
5652 clipper.Begin(items_count: items.Size);
5653 while (clipper.Step())
5654 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
5655 {
5656 // Display a data item
5657 MyItem* item = &items[row_n];
5658 ImGui::PushID(int_id: item->ID);
5659 ImGui::TableNextRow();
5660 ImGui::TableNextColumn();
5661 ImGui::Text(fmt: "%04d", item->ID);
5662 ImGui::TableNextColumn();
5663 ImGui::TextUnformatted(text: item->Name);
5664 ImGui::TableNextColumn();
5665 ImGui::SmallButton(label: "None");
5666 ImGui::TableNextColumn();
5667 ImGui::Text(fmt: "%d", item->Quantity);
5668 ImGui::PopID();
5669 }
5670 ImGui::EndTable();
5671 }
5672 ImGui::TreePop();
5673 }
5674
5675 // In this example we'll expose most table flags and settings.
5676 // For specific flags and settings refer to the corresponding section for more detailed explanation.
5677 // This section is mostly useful to experiment with combining certain flags or settings with each others.
5678 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
5679 if (open_action != -1)
5680 ImGui::SetNextItemOpen(is_open: open_action != 0);
5681 IMGUI_DEMO_MARKER("Tables/Advanced");
5682 if (ImGui::TreeNode(label: "Advanced"))
5683 {
5684 static ImGuiTableFlags flags =
5685 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
5686 | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
5687 | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
5688 | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
5689 | ImGuiTableFlags_SizingFixedFit;
5690 static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
5691
5692 enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
5693 static int contents_type = CT_SelectableSpanRow;
5694 const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
5695 static int freeze_cols = 1;
5696 static int freeze_rows = 1;
5697 static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
5698 static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
5699 static float row_min_height = 0.0f; // Auto
5700 static float inner_width_with_scroll = 0.0f; // Auto-extend
5701 static bool outer_size_enabled = true;
5702 static bool show_headers = true;
5703 static bool show_wrapped_text = false;
5704 //static ImGuiTextFilter filter;
5705 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
5706 if (ImGui::TreeNode(label: "Options"))
5707 {
5708 // Make the UI compact because there are so many fields
5709 PushStyleCompact();
5710 ImGui::PushItemWidth(item_width: TEXT_BASE_WIDTH * 28.0f);
5711
5712 if (ImGui::TreeNodeEx(label: "Features:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5713 {
5714 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Resizable", flags: &flags, flags_value: ImGuiTableFlags_Resizable);
5715 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Reorderable", flags: &flags, flags_value: ImGuiTableFlags_Reorderable);
5716 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Hideable", flags: &flags, flags_value: ImGuiTableFlags_Hideable);
5717 ImGui::CheckboxFlags(label: "ImGuiTableFlags_Sortable", flags: &flags, flags_value: ImGuiTableFlags_Sortable);
5718 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoSavedSettings", flags: &flags, flags_value: ImGuiTableFlags_NoSavedSettings);
5719 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ContextMenuInBody", flags: &flags, flags_value: ImGuiTableFlags_ContextMenuInBody);
5720 ImGui::TreePop();
5721 }
5722
5723 if (ImGui::TreeNodeEx(label: "Decorations:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5724 {
5725 ImGui::CheckboxFlags(label: "ImGuiTableFlags_RowBg", flags: &flags, flags_value: ImGuiTableFlags_RowBg);
5726 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersV", flags: &flags, flags_value: ImGuiTableFlags_BordersV);
5727 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuterV", flags: &flags, flags_value: ImGuiTableFlags_BordersOuterV);
5728 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInnerV", flags: &flags, flags_value: ImGuiTableFlags_BordersInnerV);
5729 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersH", flags: &flags, flags_value: ImGuiTableFlags_BordersH);
5730 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersOuterH", flags: &flags, flags_value: ImGuiTableFlags_BordersOuterH);
5731 ImGui::CheckboxFlags(label: "ImGuiTableFlags_BordersInnerH", flags: &flags, flags_value: ImGuiTableFlags_BordersInnerH);
5732 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoBordersInBody", flags: &flags, flags_value: ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker(desc: "Disable vertical borders in columns Body (borders will always appear in Headers");
5733 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoBordersInBodyUntilResize", flags: &flags, flags_value: ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker(desc: "Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
5734 ImGui::TreePop();
5735 }
5736
5737 if (ImGui::TreeNodeEx(label: "Sizing:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5738 {
5739 EditTableSizingFlags(p_flags: &flags);
5740 ImGui::SameLine(); HelpMarker(desc: "In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
5741 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoHostExtendX", flags: &flags, flags_value: ImGuiTableFlags_NoHostExtendX);
5742 ImGui::SameLine(); HelpMarker(desc: "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.");
5743 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoHostExtendY", flags: &flags, flags_value: ImGuiTableFlags_NoHostExtendY);
5744 ImGui::SameLine(); HelpMarker(desc: "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.");
5745 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoKeepColumnsVisible", flags: &flags, flags_value: ImGuiTableFlags_NoKeepColumnsVisible);
5746 ImGui::SameLine(); HelpMarker(desc: "Only available if ScrollX is disabled.");
5747 ImGui::CheckboxFlags(label: "ImGuiTableFlags_PreciseWidths", flags: &flags, flags_value: ImGuiTableFlags_PreciseWidths);
5748 ImGui::SameLine(); HelpMarker(desc: "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.");
5749 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoClip", flags: &flags, flags_value: ImGuiTableFlags_NoClip);
5750 ImGui::SameLine(); HelpMarker(desc: "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.");
5751 ImGui::TreePop();
5752 }
5753
5754 if (ImGui::TreeNodeEx(label: "Padding:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5755 {
5756 ImGui::CheckboxFlags(label: "ImGuiTableFlags_PadOuterX", flags: &flags, flags_value: ImGuiTableFlags_PadOuterX);
5757 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoPadOuterX", flags: &flags, flags_value: ImGuiTableFlags_NoPadOuterX);
5758 ImGui::CheckboxFlags(label: "ImGuiTableFlags_NoPadInnerX", flags: &flags, flags_value: ImGuiTableFlags_NoPadInnerX);
5759 ImGui::TreePop();
5760 }
5761
5762 if (ImGui::TreeNodeEx(label: "Scrolling:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5763 {
5764 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollX", flags: &flags, flags_value: ImGuiTableFlags_ScrollX);
5765 ImGui::SameLine();
5766 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5767 ImGui::DragInt(label: "freeze_cols", v: &freeze_cols, v_speed: 0.2f, v_min: 0, v_max: 9, NULL, flags: ImGuiSliderFlags_NoInput);
5768 ImGui::CheckboxFlags(label: "ImGuiTableFlags_ScrollY", flags: &flags, flags_value: ImGuiTableFlags_ScrollY);
5769 ImGui::SameLine();
5770 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5771 ImGui::DragInt(label: "freeze_rows", v: &freeze_rows, v_speed: 0.2f, v_min: 0, v_max: 9, NULL, flags: ImGuiSliderFlags_NoInput);
5772 ImGui::TreePop();
5773 }
5774
5775 if (ImGui::TreeNodeEx(label: "Sorting:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5776 {
5777 ImGui::CheckboxFlags(label: "ImGuiTableFlags_SortMulti", flags: &flags, flags_value: ImGuiTableFlags_SortMulti);
5778 ImGui::SameLine(); HelpMarker(desc: "When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
5779 ImGui::CheckboxFlags(label: "ImGuiTableFlags_SortTristate", flags: &flags, flags_value: ImGuiTableFlags_SortTristate);
5780 ImGui::SameLine(); HelpMarker(desc: "When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
5781 ImGui::TreePop();
5782 }
5783
5784 if (ImGui::TreeNodeEx(label: "Headers:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5785 {
5786 ImGui::Checkbox(label: "show_headers", v: &show_headers);
5787 ImGui::CheckboxFlags(label: "ImGuiTableFlags_HighlightHoveredColumn", flags: &flags, flags_value: ImGuiTableFlags_HighlightHoveredColumn);
5788 ImGui::CheckboxFlags(label: "ImGuiTableColumnFlags_AngledHeader", flags: &columns_base_flags, flags_value: ImGuiTableColumnFlags_AngledHeader);
5789 ImGui::SameLine(); HelpMarker(desc: "Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
5790 ImGui::TreePop();
5791 }
5792
5793 if (ImGui::TreeNodeEx(label: "Other:", flags: ImGuiTreeNodeFlags_DefaultOpen))
5794 {
5795 ImGui::Checkbox(label: "show_wrapped_text", v: &show_wrapped_text);
5796
5797 ImGui::DragFloat2(label: "##OuterSize", v: &outer_size_value.x);
5798 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: ImGui::GetStyle().ItemInnerSpacing.x);
5799 ImGui::Checkbox(label: "outer_size", v: &outer_size_enabled);
5800 ImGui::SameLine();
5801 HelpMarker(desc: "If scrolling is disabled (ScrollX and ScrollY not set):\n"
5802 "- The table is output directly in the parent window.\n"
5803 "- OuterSize.x < 0.0f will right-align the table.\n"
5804 "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
5805 "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
5806
5807 // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
5808 // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
5809 ImGui::DragFloat(label: "inner_width (when ScrollX active)", v: &inner_width_with_scroll, v_speed: 1.0f, v_min: 0.0f, FLT_MAX);
5810
5811 ImGui::DragFloat(label: "row_min_height", v: &row_min_height, v_speed: 1.0f, v_min: 0.0f, FLT_MAX);
5812 ImGui::SameLine(); HelpMarker(desc: "Specify height of the Selectable item.");
5813
5814 ImGui::DragInt(label: "items_count", v: &items_count, v_speed: 0.1f, v_min: 0, v_max: 9999);
5815 ImGui::Combo(label: "items_type (first column)", current_item: &contents_type, items: contents_type_names, IM_ARRAYSIZE(contents_type_names));
5816 //filter.Draw("filter");
5817 ImGui::TreePop();
5818 }
5819
5820 ImGui::PopItemWidth();
5821 PopStyleCompact();
5822 ImGui::Spacing();
5823 ImGui::TreePop();
5824 }
5825
5826 // Update item list if we changed the number of items
5827 static ImVector<MyItem> items;
5828 static ImVector<int> selection;
5829 static bool items_need_sort = false;
5830 if (items.Size != items_count)
5831 {
5832 items.resize(new_size: items_count, v: MyItem());
5833 for (int n = 0; n < items_count; n++)
5834 {
5835 const int template_n = n % IM_ARRAYSIZE(template_items_names);
5836 MyItem& item = items[n];
5837 item.ID = n;
5838 item.Name = template_items_names[template_n];
5839 item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
5840 }
5841 }
5842
5843 const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
5844 const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
5845 ImVec2 table_scroll_cur, table_scroll_max; // For debug display
5846 const ImDrawList* table_draw_list = NULL; // "
5847
5848 // Submit table
5849 const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
5850 if (ImGui::BeginTable(str_id: "table_advanced", column: 6, flags, outer_size: outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width: inner_width_to_use))
5851 {
5852 // Declare columns
5853 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
5854 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
5855 ImGui::TableSetupColumn(label: "ID", flags: columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, init_width_or_weight: 0.0f, user_id: MyItemColumnID_ID);
5856 ImGui::TableSetupColumn(label: "Name", flags: columns_base_flags | ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 0.0f, user_id: MyItemColumnID_Name);
5857 ImGui::TableSetupColumn(label: "Action", flags: columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, init_width_or_weight: 0.0f, user_id: MyItemColumnID_Action);
5858 ImGui::TableSetupColumn(label: "Quantity", flags: columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, init_width_or_weight: 0.0f, user_id: MyItemColumnID_Quantity);
5859 ImGui::TableSetupColumn(label: "Description", flags: columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), init_width_or_weight: 0.0f, user_id: MyItemColumnID_Description);
5860 ImGui::TableSetupColumn(label: "Hidden", flags: columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
5861 ImGui::TableSetupScrollFreeze(cols: freeze_cols, rows: freeze_rows);
5862
5863 // Sort our data if sort specs have been changed!
5864 ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
5865 if (sort_specs && sort_specs->SpecsDirty)
5866 items_need_sort = true;
5867 if (sort_specs && items_need_sort && items.Size > 1)
5868 {
5869 MyItem::SortWithSortSpecs(sort_specs, items: items.Data, items_count: items.Size);
5870 sort_specs->SpecsDirty = false;
5871 }
5872 items_need_sort = false;
5873
5874 // Take note of whether we are currently sorting based on the Quantity field,
5875 // we will use this to trigger sorting when we know the data of this column has been modified.
5876 const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(column_n: 3) & ImGuiTableColumnFlags_IsSorted) != 0;
5877
5878 // Show headers
5879 if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
5880 ImGui::TableAngledHeadersRow();
5881 if (show_headers)
5882 ImGui::TableHeadersRow();
5883
5884 // Show data
5885 // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
5886 ImGui::PushButtonRepeat(repeat: true);
5887#if 1
5888 // Demonstrate using clipper for large vertical lists
5889 ImGuiListClipper clipper;
5890 clipper.Begin(items_count: items.Size);
5891 while (clipper.Step())
5892 {
5893 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
5894#else
5895 // Without clipper
5896 {
5897 for (int row_n = 0; row_n < items.Size; row_n++)
5898#endif
5899 {
5900 MyItem* item = &items[row_n];
5901 //if (!filter.PassFilter(item->Name))
5902 // continue;
5903
5904 const bool item_is_selected = selection.contains(v: item->ID);
5905 ImGui::PushID(int_id: item->ID);
5906 ImGui::TableNextRow(row_flags: ImGuiTableRowFlags_None, min_row_height: row_min_height);
5907
5908 // For the demo purpose we can select among different type of items submitted in the first column
5909 ImGui::TableSetColumnIndex(column_n: 0);
5910 char label[32];
5911 sprintf(s: label, format: "%04d", item->ID);
5912 if (contents_type == CT_Text)
5913 ImGui::TextUnformatted(text: label);
5914 else if (contents_type == CT_Button)
5915 ImGui::Button(label);
5916 else if (contents_type == CT_SmallButton)
5917 ImGui::SmallButton(label);
5918 else if (contents_type == CT_FillButton)
5919 ImGui::Button(label, size: ImVec2(-FLT_MIN, 0.0f));
5920 else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
5921 {
5922 ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
5923 if (ImGui::Selectable(label, selected: item_is_selected, flags: selectable_flags, size: ImVec2(0, row_min_height)))
5924 {
5925 if (ImGui::GetIO().KeyCtrl)
5926 {
5927 if (item_is_selected)
5928 selection.find_erase_unsorted(v: item->ID);
5929 else
5930 selection.push_back(v: item->ID);
5931 }
5932 else
5933 {
5934 selection.clear();
5935 selection.push_back(v: item->ID);
5936 }
5937 }
5938 }
5939
5940 if (ImGui::TableSetColumnIndex(column_n: 1))
5941 ImGui::TextUnformatted(text: item->Name);
5942
5943 // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
5944 // and we are currently sorting on the column showing the Quantity.
5945 // To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
5946 // You will probably need some extra logic if you want to automatically sort when a specific entry changes.
5947 if (ImGui::TableSetColumnIndex(column_n: 2))
5948 {
5949 if (ImGui::SmallButton(label: "Chop")) { item->Quantity += 1; }
5950 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
5951 ImGui::SameLine();
5952 if (ImGui::SmallButton(label: "Eat")) { item->Quantity -= 1; }
5953 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
5954 }
5955
5956 if (ImGui::TableSetColumnIndex(column_n: 3))
5957 ImGui::Text(fmt: "%d", item->Quantity);
5958
5959 ImGui::TableSetColumnIndex(column_n: 4);
5960 if (show_wrapped_text)
5961 ImGui::TextWrapped(fmt: "Lorem ipsum dolor sit amet");
5962 else
5963 ImGui::Text(fmt: "Lorem ipsum dolor sit amet");
5964
5965 if (ImGui::TableSetColumnIndex(column_n: 5))
5966 ImGui::Text(fmt: "1234");
5967
5968 ImGui::PopID();
5969 }
5970 }
5971 ImGui::PopButtonRepeat();
5972
5973 // Store some info to display debug details below
5974 table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
5975 table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
5976 table_draw_list = ImGui::GetWindowDrawList();
5977 ImGui::EndTable();
5978 }
5979 static bool show_debug_details = false;
5980 ImGui::Checkbox(label: "Debug details", v: &show_debug_details);
5981 if (show_debug_details && table_draw_list)
5982 {
5983 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: 0.0f);
5984 const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
5985 if (table_draw_list == parent_draw_list)
5986 ImGui::Text(fmt: ": DrawCmd: +%d (in same window)",
5987 table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
5988 else
5989 ImGui::Text(fmt: ": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
5990 table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
5991 }
5992 ImGui::TreePop();
5993 }
5994
5995 ImGui::PopID();
5996
5997 ShowDemoWindowColumns();
5998
5999 if (disable_indent)
6000 ImGui::PopStyleVar();
6001}
6002
6003// Demonstrate old/legacy Columns API!
6004// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
6005static void ShowDemoWindowColumns()
6006{
6007 IMGUI_DEMO_MARKER("Columns (legacy API)");
6008 bool open = ImGui::TreeNode(label: "Legacy Columns API");
6009 ImGui::SameLine();
6010 HelpMarker(desc: "Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
6011 if (!open)
6012 return;
6013
6014 // Basic columns
6015 IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
6016 if (ImGui::TreeNode(label: "Basic"))
6017 {
6018 ImGui::Text(fmt: "Without border:");
6019 ImGui::Columns(count: 3, id: "mycolumns3", border: false); // 3-ways, no border
6020 ImGui::Separator();
6021 for (int n = 0; n < 14; n++)
6022 {
6023 char label[32];
6024 sprintf(s: label, format: "Item %d", n);
6025 if (ImGui::Selectable(label)) {}
6026 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
6027 ImGui::NextColumn();
6028 }
6029 ImGui::Columns(count: 1);
6030 ImGui::Separator();
6031
6032 ImGui::Text(fmt: "With border:");
6033 ImGui::Columns(count: 4, id: "mycolumns"); // 4-ways, with border
6034 ImGui::Separator();
6035 ImGui::Text(fmt: "ID"); ImGui::NextColumn();
6036 ImGui::Text(fmt: "Name"); ImGui::NextColumn();
6037 ImGui::Text(fmt: "Path"); ImGui::NextColumn();
6038 ImGui::Text(fmt: "Hovered"); ImGui::NextColumn();
6039 ImGui::Separator();
6040 const char* names[3] = { "One", "Two", "Three" };
6041 const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
6042 static int selected = -1;
6043 for (int i = 0; i < 3; i++)
6044 {
6045 char label[32];
6046 sprintf(s: label, format: "%04d", i);
6047 if (ImGui::Selectable(label, selected: selected == i, flags: ImGuiSelectableFlags_SpanAllColumns))
6048 selected = i;
6049 bool hovered = ImGui::IsItemHovered();
6050 ImGui::NextColumn();
6051 ImGui::Text(fmt: names[i]); ImGui::NextColumn();
6052 ImGui::Text(fmt: paths[i]); ImGui::NextColumn();
6053 ImGui::Text(fmt: "%d", hovered); ImGui::NextColumn();
6054 }
6055 ImGui::Columns(count: 1);
6056 ImGui::Separator();
6057 ImGui::TreePop();
6058 }
6059
6060 IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
6061 if (ImGui::TreeNode(label: "Borders"))
6062 {
6063 // NB: Future columns API should allow automatic horizontal borders.
6064 static bool h_borders = true;
6065 static bool v_borders = true;
6066 static int columns_count = 4;
6067 const int lines_count = 3;
6068 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6069 ImGui::DragInt(label: "##columns_count", v: &columns_count, v_speed: 0.1f, v_min: 2, v_max: 10, format: "%d columns");
6070 if (columns_count < 2)
6071 columns_count = 2;
6072 ImGui::SameLine();
6073 ImGui::Checkbox(label: "horizontal", v: &h_borders);
6074 ImGui::SameLine();
6075 ImGui::Checkbox(label: "vertical", v: &v_borders);
6076 ImGui::Columns(count: columns_count, NULL, border: v_borders);
6077 for (int i = 0; i < columns_count * lines_count; i++)
6078 {
6079 if (h_borders && ImGui::GetColumnIndex() == 0)
6080 ImGui::Separator();
6081 ImGui::Text(fmt: "%c%c%c", 'a' + i, 'a' + i, 'a' + i);
6082 ImGui::Text(fmt: "Width %.2f", ImGui::GetColumnWidth());
6083 ImGui::Text(fmt: "Avail %.2f", ImGui::GetContentRegionAvail().x);
6084 ImGui::Text(fmt: "Offset %.2f", ImGui::GetColumnOffset());
6085 ImGui::Text(fmt: "Long text that is likely to clip");
6086 ImGui::Button(label: "Button", size: ImVec2(-FLT_MIN, 0.0f));
6087 ImGui::NextColumn();
6088 }
6089 ImGui::Columns(count: 1);
6090 if (h_borders)
6091 ImGui::Separator();
6092 ImGui::TreePop();
6093 }
6094
6095 // Create multiple items in a same cell before switching to next column
6096 IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
6097 if (ImGui::TreeNode(label: "Mixed items"))
6098 {
6099 ImGui::Columns(count: 3, id: "mixed");
6100 ImGui::Separator();
6101
6102 ImGui::Text(fmt: "Hello");
6103 ImGui::Button(label: "Banana");
6104 ImGui::NextColumn();
6105
6106 ImGui::Text(fmt: "ImGui");
6107 ImGui::Button(label: "Apple");
6108 static float foo = 1.0f;
6109 ImGui::InputFloat(label: "red", v: &foo, step: 0.05f, step_fast: 0, format: "%.3f");
6110 ImGui::Text(fmt: "An extra line here.");
6111 ImGui::NextColumn();
6112
6113 ImGui::Text(fmt: "Sailor");
6114 ImGui::Button(label: "Corniflower");
6115 static float bar = 1.0f;
6116 ImGui::InputFloat(label: "blue", v: &bar, step: 0.05f, step_fast: 0, format: "%.3f");
6117 ImGui::NextColumn();
6118
6119 if (ImGui::CollapsingHeader(label: "Category A")) { ImGui::Text(fmt: "Blah blah blah"); } ImGui::NextColumn();
6120 if (ImGui::CollapsingHeader(label: "Category B")) { ImGui::Text(fmt: "Blah blah blah"); } ImGui::NextColumn();
6121 if (ImGui::CollapsingHeader(label: "Category C")) { ImGui::Text(fmt: "Blah blah blah"); } ImGui::NextColumn();
6122 ImGui::Columns(count: 1);
6123 ImGui::Separator();
6124 ImGui::TreePop();
6125 }
6126
6127 // Word wrapping
6128 IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
6129 if (ImGui::TreeNode(label: "Word-wrapping"))
6130 {
6131 ImGui::Columns(count: 2, id: "word-wrapping");
6132 ImGui::Separator();
6133 ImGui::TextWrapped(fmt: "The quick brown fox jumps over the lazy dog.");
6134 ImGui::TextWrapped(fmt: "Hello Left");
6135 ImGui::NextColumn();
6136 ImGui::TextWrapped(fmt: "The quick brown fox jumps over the lazy dog.");
6137 ImGui::TextWrapped(fmt: "Hello Right");
6138 ImGui::Columns(count: 1);
6139 ImGui::Separator();
6140 ImGui::TreePop();
6141 }
6142
6143 IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
6144 if (ImGui::TreeNode(label: "Horizontal Scrolling"))
6145 {
6146 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
6147 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
6148 ImGui::BeginChild(str_id: "##ScrollingRegion", size: child_size, child_flags: ImGuiChildFlags_None, window_flags: ImGuiWindowFlags_HorizontalScrollbar);
6149 ImGui::Columns(count: 10);
6150
6151 // Also demonstrate using clipper for large vertical lists
6152 int ITEMS_COUNT = 2000;
6153 ImGuiListClipper clipper;
6154 clipper.Begin(items_count: ITEMS_COUNT);
6155 while (clipper.Step())
6156 {
6157 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
6158 for (int j = 0; j < 10; j++)
6159 {
6160 ImGui::Text(fmt: "Line %d Column %d...", i, j);
6161 ImGui::NextColumn();
6162 }
6163 }
6164 ImGui::Columns(count: 1);
6165 ImGui::EndChild();
6166 ImGui::TreePop();
6167 }
6168
6169 IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
6170 if (ImGui::TreeNode(label: "Tree"))
6171 {
6172 ImGui::Columns(count: 2, id: "tree", border: true);
6173 for (int x = 0; x < 3; x++)
6174 {
6175 bool open1 = ImGui::TreeNode(ptr_id: (void*)(intptr_t)x, fmt: "Node%d", x);
6176 ImGui::NextColumn();
6177 ImGui::Text(fmt: "Node contents");
6178 ImGui::NextColumn();
6179 if (open1)
6180 {
6181 for (int y = 0; y < 3; y++)
6182 {
6183 bool open2 = ImGui::TreeNode(ptr_id: (void*)(intptr_t)y, fmt: "Node%d.%d", x, y);
6184 ImGui::NextColumn();
6185 ImGui::Text(fmt: "Node contents");
6186 if (open2)
6187 {
6188 ImGui::Text(fmt: "Even more contents");
6189 if (ImGui::TreeNode(label: "Tree in column"))
6190 {
6191 ImGui::Text(fmt: "The quick brown fox jumps over the lazy dog");
6192 ImGui::TreePop();
6193 }
6194 }
6195 ImGui::NextColumn();
6196 if (open2)
6197 ImGui::TreePop();
6198 }
6199 ImGui::TreePop();
6200 }
6201 }
6202 ImGui::Columns(count: 1);
6203 ImGui::TreePop();
6204 }
6205
6206 ImGui::TreePop();
6207}
6208
6209static void ShowDemoWindowInputs()
6210{
6211 IMGUI_DEMO_MARKER("Inputs & Focus");
6212 if (ImGui::CollapsingHeader(label: "Inputs & Focus"))
6213 {
6214 ImGuiIO& io = ImGui::GetIO();
6215
6216 // Display inputs submitted to ImGuiIO
6217 IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
6218 ImGui::SetNextItemOpen(is_open: true, cond: ImGuiCond_Once);
6219 if (ImGui::TreeNode(label: "Inputs"))
6220 {
6221 HelpMarker(
6222 desc: "This is a simplified view. See more detailed input state:\n"
6223 "- in 'Tools->Metrics/Debugger->Inputs'.\n"
6224 "- in 'Tools->Debug Log->IO'.");
6225 if (ImGui::IsMousePosValid())
6226 ImGui::Text(fmt: "Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
6227 else
6228 ImGui::Text(fmt: "Mouse pos: <INVALID>");
6229 ImGui::Text(fmt: "Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
6230 ImGui::Text(fmt: "Mouse down:");
6231 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(button: i)) { ImGui::SameLine(); ImGui::Text(fmt: "b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
6232 ImGui::Text(fmt: "Mouse wheel: %.1f", io.MouseWheel);
6233
6234 // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
6235 // displaying the data for old/new backends.
6236 // User code should never have to go through such hoops!
6237 // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
6238#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
6239 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
6240 ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
6241#else
6242 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key >= 0 && key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
6243 ImGuiKey start_key = (ImGuiKey)0;
6244#endif
6245 ImGui::Text(fmt: "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(fmt: (key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); }
6246 ImGui::Text(fmt: "Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
6247 ImGui::Text(fmt: "Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text(fmt: "\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
6248
6249 ImGui::TreePop();
6250 }
6251
6252 // Display ImGuiIO output flags
6253 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
6254 ImGui::SetNextItemOpen(is_open: true, cond: ImGuiCond_Once);
6255 if (ImGui::TreeNode(label: "Outputs"))
6256 {
6257 HelpMarker(
6258 desc: "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
6259 "to instruct your application of how to route inputs. Typically, when a value is true, it means "
6260 "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
6261 "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
6262 "and underlying application should ignore mouse inputs (in practice there are many and more subtle "
6263 "rules leading to how those flags are set).");
6264 ImGui::Text(fmt: "io.WantCaptureMouse: %d", io.WantCaptureMouse);
6265 ImGui::Text(fmt: "io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
6266 ImGui::Text(fmt: "io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
6267 ImGui::Text(fmt: "io.WantTextInput: %d", io.WantTextInput);
6268 ImGui::Text(fmt: "io.WantSetMousePos: %d", io.WantSetMousePos);
6269 ImGui::Text(fmt: "io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
6270
6271 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
6272 if (ImGui::TreeNode(label: "WantCapture override"))
6273 {
6274 HelpMarker(
6275 desc: "Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
6276 "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
6277 "and true when clicking.");
6278 static int capture_override_mouse = -1;
6279 static int capture_override_keyboard = -1;
6280 const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
6281 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
6282 ImGui::SliderInt(label: "SetNextFrameWantCaptureMouse() on hover", v: &capture_override_mouse, v_min: -1, v_max: +1, format: capture_override_desc[capture_override_mouse + 1], flags: ImGuiSliderFlags_AlwaysClamp);
6283 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
6284 ImGui::SliderInt(label: "SetNextFrameWantCaptureKeyboard() on hover", v: &capture_override_keyboard, v_min: -1, v_max: +1, format: capture_override_desc[capture_override_keyboard + 1], flags: ImGuiSliderFlags_AlwaysClamp);
6285
6286 ImGui::ColorButton(desc_id: "##panel", col: ImVec4(0.7f, 0.1f, 0.7f, 1.0f), flags: ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, size: ImVec2(128.0f, 96.0f)); // Dummy item
6287 if (ImGui::IsItemHovered() && capture_override_mouse != -1)
6288 ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
6289 if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
6290 ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
6291
6292 ImGui::TreePop();
6293 }
6294 ImGui::TreePop();
6295 }
6296
6297 // Display mouse cursors
6298 IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
6299 if (ImGui::TreeNode(label: "Mouse Cursors"))
6300 {
6301 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
6302 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
6303
6304 ImGuiMouseCursor current = ImGui::GetMouseCursor();
6305 ImGui::Text(fmt: "Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
6306 ImGui::BeginDisabled(disabled: true);
6307 ImGui::CheckboxFlags(label: "io.BackendFlags: HasMouseCursors", flags: &io.BackendFlags, flags_value: ImGuiBackendFlags_HasMouseCursors);
6308 ImGui::EndDisabled();
6309
6310 ImGui::Text(fmt: "Hover to see mouse cursors:");
6311 ImGui::SameLine(); HelpMarker(
6312 desc: "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
6313 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
6314 "otherwise your backend needs to handle it.");
6315 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
6316 {
6317 char label[32];
6318 sprintf(s: label, format: "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
6319 ImGui::Bullet(); ImGui::Selectable(label, selected: false);
6320 if (ImGui::IsItemHovered())
6321 ImGui::SetMouseCursor(i);
6322 }
6323 ImGui::TreePop();
6324 }
6325
6326 IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
6327 if (ImGui::TreeNode(label: "Tabbing"))
6328 {
6329 ImGui::Text(fmt: "Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
6330 static char buf[32] = "hello";
6331 ImGui::InputText(label: "1", buf, IM_ARRAYSIZE(buf));
6332 ImGui::InputText(label: "2", buf, IM_ARRAYSIZE(buf));
6333 ImGui::InputText(label: "3", buf, IM_ARRAYSIZE(buf));
6334 ImGui::PushTabStop(tab_stop: false);
6335 ImGui::InputText(label: "4 (tab skip)", buf, IM_ARRAYSIZE(buf));
6336 ImGui::SameLine(); HelpMarker(desc: "Item won't be cycled through when using TAB or Shift+Tab.");
6337 ImGui::PopTabStop();
6338 ImGui::InputText(label: "5", buf, IM_ARRAYSIZE(buf));
6339 ImGui::TreePop();
6340 }
6341
6342 IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
6343 if (ImGui::TreeNode(label: "Focus from code"))
6344 {
6345 bool focus_1 = ImGui::Button(label: "Focus on 1"); ImGui::SameLine();
6346 bool focus_2 = ImGui::Button(label: "Focus on 2"); ImGui::SameLine();
6347 bool focus_3 = ImGui::Button(label: "Focus on 3");
6348 int has_focus = 0;
6349 static char buf[128] = "click on a button to set focus";
6350
6351 if (focus_1) ImGui::SetKeyboardFocusHere();
6352 ImGui::InputText(label: "1", buf, IM_ARRAYSIZE(buf));
6353 if (ImGui::IsItemActive()) has_focus = 1;
6354
6355 if (focus_2) ImGui::SetKeyboardFocusHere();
6356 ImGui::InputText(label: "2", buf, IM_ARRAYSIZE(buf));
6357 if (ImGui::IsItemActive()) has_focus = 2;
6358
6359 ImGui::PushTabStop(tab_stop: false);
6360 if (focus_3) ImGui::SetKeyboardFocusHere();
6361 ImGui::InputText(label: "3 (tab skip)", buf, IM_ARRAYSIZE(buf));
6362 if (ImGui::IsItemActive()) has_focus = 3;
6363 ImGui::SameLine(); HelpMarker(desc: "Item won't be cycled through when using TAB or Shift+Tab.");
6364 ImGui::PopTabStop();
6365
6366 if (has_focus)
6367 ImGui::Text(fmt: "Item with focus: %d", has_focus);
6368 else
6369 ImGui::Text(fmt: "Item with focus: <none>");
6370
6371 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
6372 static float f3[3] = { 0.0f, 0.0f, 0.0f };
6373 int focus_ahead = -1;
6374 if (ImGui::Button(label: "Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
6375 if (ImGui::Button(label: "Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
6376 if (ImGui::Button(label: "Focus on Z")) { focus_ahead = 2; }
6377 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
6378 ImGui::SliderFloat3(label: "Float3", v: &f3[0], v_min: 0.0f, v_max: 1.0f);
6379
6380 ImGui::TextWrapped(fmt: "NB: Cursor & selection are preserved when refocusing last used item in code.");
6381 ImGui::TreePop();
6382 }
6383
6384 IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
6385 if (ImGui::TreeNode(label: "Dragging"))
6386 {
6387 ImGui::TextWrapped(fmt: "You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
6388 for (int button = 0; button < 3; button++)
6389 {
6390 ImGui::Text(fmt: "IsMouseDragging(%d):", button);
6391 ImGui::Text(fmt: " w/ default threshold: %d,", ImGui::IsMouseDragging(button));
6392 ImGui::Text(fmt: " w/ zero threshold: %d,", ImGui::IsMouseDragging(button, lock_threshold: 0.0f));
6393 ImGui::Text(fmt: " w/ large threshold: %d,", ImGui::IsMouseDragging(button, lock_threshold: 20.0f));
6394 }
6395
6396 ImGui::Button(label: "Drag Me");
6397 if (ImGui::IsItemActive())
6398 ImGui::GetForegroundDrawList()->AddLine(p1: io.MouseClickedPos[0], p2: io.MousePos, col: ImGui::GetColorU32(idx: ImGuiCol_Button), thickness: 4.0f); // Draw a line between the button and the mouse cursor
6399
6400 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
6401 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
6402 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
6403 ImVec2 value_raw = ImGui::GetMouseDragDelta(button: 0, lock_threshold: 0.0f);
6404 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(button: 0);
6405 ImVec2 mouse_delta = io.MouseDelta;
6406 ImGui::Text(fmt: "GetMouseDragDelta(0):");
6407 ImGui::Text(fmt: " w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
6408 ImGui::Text(fmt: " w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
6409 ImGui::Text(fmt: "io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
6410 ImGui::TreePop();
6411 }
6412 }
6413}
6414
6415//-----------------------------------------------------------------------------
6416// [SECTION] About Window / ShowAboutWindow()
6417// Access from Dear ImGui Demo -> Tools -> About
6418//-----------------------------------------------------------------------------
6419
6420void ImGui::ShowAboutWindow(bool* p_open)
6421{
6422 if (!ImGui::Begin(name: "About Dear ImGui", p_open, flags: ImGuiWindowFlags_AlwaysAutoResize))
6423 {
6424 ImGui::End();
6425 return;
6426 }
6427 IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
6428 ImGui::Text(fmt: "Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
6429 ImGui::Separator();
6430 ImGui::Text(fmt: "By Omar Cornut and all Dear ImGui contributors.");
6431 ImGui::Text(fmt: "Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
6432 ImGui::Text(fmt: "If your company uses this, please consider funding the project.");
6433
6434 static bool show_config_info = false;
6435 ImGui::Checkbox(label: "Config/Build Information", v: &show_config_info);
6436 if (show_config_info)
6437 {
6438 ImGuiIO& io = ImGui::GetIO();
6439 ImGuiStyle& style = ImGui::GetStyle();
6440
6441 bool copy_to_clipboard = ImGui::Button(label: "Copy to clipboard");
6442 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
6443 ImGui::BeginChild(id: ImGui::GetID(str_id: "cfg_infos"), size: child_size, child_flags: ImGuiChildFlags_FrameStyle);
6444 if (copy_to_clipboard)
6445 {
6446 ImGui::LogToClipboard();
6447 ImGui::LogText(fmt: "```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
6448 }
6449
6450 ImGui::Text(fmt: "Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
6451 ImGui::Separator();
6452 ImGui::Text(fmt: "sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
6453 ImGui::Text(fmt: "define: __cplusplus=%d", (int)__cplusplus);
6454#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6455 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
6456#endif
6457#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
6458 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_KEYIO");
6459#endif
6460#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
6461 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
6462#endif
6463#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
6464 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
6465#endif
6466#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
6467 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
6468#endif
6469#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
6470 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
6471#endif
6472#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
6473 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
6474#endif
6475#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
6476 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
6477#endif
6478#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
6479 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
6480#endif
6481#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
6482 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
6483#endif
6484#ifdef IMGUI_USE_BGRA_PACKED_COLOR
6485 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
6486#endif
6487#ifdef _WIN32
6488 ImGui::Text("define: _WIN32");
6489#endif
6490#ifdef _WIN64
6491 ImGui::Text("define: _WIN64");
6492#endif
6493#ifdef __linux__
6494 ImGui::Text(fmt: "define: __linux__");
6495#endif
6496#ifdef __APPLE__
6497 ImGui::Text("define: __APPLE__");
6498#endif
6499#ifdef _MSC_VER
6500 ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
6501#endif
6502#ifdef _MSVC_LANG
6503 ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
6504#endif
6505#ifdef __MINGW32__
6506 ImGui::Text("define: __MINGW32__");
6507#endif
6508#ifdef __MINGW64__
6509 ImGui::Text("define: __MINGW64__");
6510#endif
6511#ifdef __GNUC__
6512 ImGui::Text(fmt: "define: __GNUC__=%d", (int)__GNUC__);
6513#endif
6514#ifdef __clang_version__
6515 ImGui::Text(fmt: "define: __clang_version__=%s", __clang_version__);
6516#endif
6517#ifdef __EMSCRIPTEN__
6518 ImGui::Text("define: __EMSCRIPTEN__");
6519#endif
6520#ifdef IMGUI_HAS_VIEWPORT
6521 ImGui::Text(fmt: "define: IMGUI_HAS_VIEWPORT");
6522#endif
6523#ifdef IMGUI_HAS_DOCK
6524 ImGui::Text(fmt: "define: IMGUI_HAS_DOCK");
6525#endif
6526 ImGui::Separator();
6527 ImGui::Text(fmt: "io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
6528 ImGui::Text(fmt: "io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
6529 ImGui::Text(fmt: "io.ConfigFlags: 0x%08X", io.ConfigFlags);
6530 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(fmt: " NavEnableKeyboard");
6531 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(fmt: " NavEnableGamepad");
6532 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(fmt: " NavEnableSetMousePos");
6533 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(fmt: " NavNoCaptureKeyboard");
6534 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(fmt: " NoMouse");
6535 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(fmt: " NoMouseCursorChange");
6536 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(fmt: " DockingEnable");
6537 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(fmt: " ViewportsEnable");
6538 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(fmt: " DpiEnableScaleViewports");
6539 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(fmt: " DpiEnableScaleFonts");
6540 if (io.MouseDrawCursor) ImGui::Text(fmt: "io.MouseDrawCursor");
6541 if (io.ConfigViewportsNoAutoMerge) ImGui::Text(fmt: "io.ConfigViewportsNoAutoMerge");
6542 if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text(fmt: "io.ConfigViewportsNoTaskBarIcon");
6543 if (io.ConfigViewportsNoDecoration) ImGui::Text(fmt: "io.ConfigViewportsNoDecoration");
6544 if (io.ConfigViewportsNoDefaultParent) ImGui::Text(fmt: "io.ConfigViewportsNoDefaultParent");
6545 if (io.ConfigDockingNoSplit) ImGui::Text(fmt: "io.ConfigDockingNoSplit");
6546 if (io.ConfigDockingWithShift) ImGui::Text(fmt: "io.ConfigDockingWithShift");
6547 if (io.ConfigDockingAlwaysTabBar) ImGui::Text(fmt: "io.ConfigDockingAlwaysTabBar");
6548 if (io.ConfigDockingTransparentPayload) ImGui::Text(fmt: "io.ConfigDockingTransparentPayload");
6549 if (io.ConfigMacOSXBehaviors) ImGui::Text(fmt: "io.ConfigMacOSXBehaviors");
6550 if (io.ConfigInputTextCursorBlink) ImGui::Text(fmt: "io.ConfigInputTextCursorBlink");
6551 if (io.ConfigWindowsResizeFromEdges) ImGui::Text(fmt: "io.ConfigWindowsResizeFromEdges");
6552 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text(fmt: "io.ConfigWindowsMoveFromTitleBarOnly");
6553 if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text(fmt: "io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
6554 ImGui::Text(fmt: "io.BackendFlags: 0x%08X", io.BackendFlags);
6555 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(fmt: " HasGamepad");
6556 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(fmt: " HasMouseCursors");
6557 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(fmt: " HasSetMousePos");
6558 if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(fmt: " PlatformHasViewports");
6559 if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(fmt: " HasMouseHoveredViewport");
6560 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(fmt: " RendererHasVtxOffset");
6561 if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(fmt: " RendererHasViewports");
6562 ImGui::Separator();
6563 ImGui::Text(fmt: "io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
6564 ImGui::Text(fmt: "io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
6565 ImGui::Text(fmt: "io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
6566 ImGui::Separator();
6567 ImGui::Text(fmt: "style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
6568 ImGui::Text(fmt: "style.WindowBorderSize: %.2f", style.WindowBorderSize);
6569 ImGui::Text(fmt: "style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
6570 ImGui::Text(fmt: "style.FrameRounding: %.2f", style.FrameRounding);
6571 ImGui::Text(fmt: "style.FrameBorderSize: %.2f", style.FrameBorderSize);
6572 ImGui::Text(fmt: "style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
6573 ImGui::Text(fmt: "style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
6574
6575 if (copy_to_clipboard)
6576 {
6577 ImGui::LogText(fmt: "\n```\n");
6578 ImGui::LogFinish();
6579 }
6580 ImGui::EndChild();
6581 }
6582 ImGui::End();
6583}
6584
6585//-----------------------------------------------------------------------------
6586// [SECTION] Style Editor / ShowStyleEditor()
6587//-----------------------------------------------------------------------------
6588// - ShowFontSelector()
6589// - ShowStyleSelector()
6590// - ShowStyleEditor()
6591//-----------------------------------------------------------------------------
6592
6593// Forward declare ShowFontAtlas() which isn't worth putting in public API yet
6594namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
6595
6596// Demo helper function to select among loaded fonts.
6597// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one.
6598void ImGui::ShowFontSelector(const char* label)
6599{
6600 ImGuiIO& io = ImGui::GetIO();
6601 ImFont* font_current = ImGui::GetFont();
6602 if (ImGui::BeginCombo(label, preview_value: font_current->GetDebugName()))
6603 {
6604 for (ImFont* font : io.Fonts->Fonts)
6605 {
6606 ImGui::PushID(ptr_id: (void*)font);
6607 if (ImGui::Selectable(label: font->GetDebugName(), selected: font == font_current))
6608 io.FontDefault = font;
6609 ImGui::PopID();
6610 }
6611 ImGui::EndCombo();
6612 }
6613 ImGui::SameLine();
6614 HelpMarker(
6615 desc: "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
6616 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
6617 "- Read FAQ and docs/FONTS.md for more details.\n"
6618 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
6619}
6620
6621// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
6622// Here we use the simplified Combo() api that packs items into a single literal string.
6623// Useful for quick combo boxes where the choices are known locally.
6624bool ImGui::ShowStyleSelector(const char* label)
6625{
6626 static int style_idx = -1;
6627 if (ImGui::Combo(label, current_item: &style_idx, items_separated_by_zeros: "Dark\0Light\0Classic\0"))
6628 {
6629 switch (style_idx)
6630 {
6631 case 0: ImGui::StyleColorsDark(); break;
6632 case 1: ImGui::StyleColorsLight(); break;
6633 case 2: ImGui::StyleColorsClassic(); break;
6634 }
6635 return true;
6636 }
6637 return false;
6638}
6639
6640void ImGui::ShowStyleEditor(ImGuiStyle* ref)
6641{
6642 IMGUI_DEMO_MARKER("Tools/Style Editor");
6643 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
6644 // (without a reference style pointer, we will use one compared locally as a reference)
6645 ImGuiStyle& style = ImGui::GetStyle();
6646 static ImGuiStyle ref_saved_style;
6647
6648 // Default to using internal storage as reference
6649 static bool init = true;
6650 if (init && ref == NULL)
6651 ref_saved_style = style;
6652 init = false;
6653 if (ref == NULL)
6654 ref = &ref_saved_style;
6655
6656 ImGui::PushItemWidth(item_width: ImGui::GetWindowWidth() * 0.50f);
6657
6658 if (ImGui::ShowStyleSelector(label: "Colors##Selector"))
6659 ref_saved_style = style;
6660 ImGui::ShowFontSelector(label: "Fonts##Selector");
6661
6662 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
6663 if (ImGui::SliderFloat(label: "FrameRounding", v: &style.FrameRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f"))
6664 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
6665 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox(label: "WindowBorder", v: &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
6666 ImGui::SameLine();
6667 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox(label: "FrameBorder", v: &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } }
6668 ImGui::SameLine();
6669 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox(label: "PopupBorder", v: &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } }
6670
6671 // Save/Revert button
6672 if (ImGui::Button(label: "Save Ref"))
6673 *ref = ref_saved_style = style;
6674 ImGui::SameLine();
6675 if (ImGui::Button(label: "Revert Ref"))
6676 style = *ref;
6677 ImGui::SameLine();
6678 HelpMarker(
6679 desc: "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
6680 "Use \"Export\" below to save them somewhere.");
6681
6682 ImGui::Separator();
6683
6684 if (ImGui::BeginTabBar(str_id: "##tabs", flags: ImGuiTabBarFlags_None))
6685 {
6686 if (ImGui::BeginTabItem(label: "Sizes"))
6687 {
6688 ImGui::SeparatorText(label: "Main");
6689 ImGui::SliderFloat2(label: "WindowPadding", v: (float*)&style.WindowPadding, v_min: 0.0f, v_max: 20.0f, format: "%.0f");
6690 ImGui::SliderFloat2(label: "FramePadding", v: (float*)&style.FramePadding, v_min: 0.0f, v_max: 20.0f, format: "%.0f");
6691 ImGui::SliderFloat2(label: "ItemSpacing", v: (float*)&style.ItemSpacing, v_min: 0.0f, v_max: 20.0f, format: "%.0f");
6692 ImGui::SliderFloat2(label: "ItemInnerSpacing", v: (float*)&style.ItemInnerSpacing, v_min: 0.0f, v_max: 20.0f, format: "%.0f");
6693 ImGui::SliderFloat2(label: "TouchExtraPadding", v: (float*)&style.TouchExtraPadding, v_min: 0.0f, v_max: 10.0f, format: "%.0f");
6694 ImGui::SliderFloat(label: "IndentSpacing", v: &style.IndentSpacing, v_min: 0.0f, v_max: 30.0f, format: "%.0f");
6695 ImGui::SliderFloat(label: "ScrollbarSize", v: &style.ScrollbarSize, v_min: 1.0f, v_max: 20.0f, format: "%.0f");
6696 ImGui::SliderFloat(label: "GrabMinSize", v: &style.GrabMinSize, v_min: 1.0f, v_max: 20.0f, format: "%.0f");
6697
6698 ImGui::SeparatorText(label: "Borders");
6699 ImGui::SliderFloat(label: "WindowBorderSize", v: &style.WindowBorderSize, v_min: 0.0f, v_max: 1.0f, format: "%.0f");
6700 ImGui::SliderFloat(label: "ChildBorderSize", v: &style.ChildBorderSize, v_min: 0.0f, v_max: 1.0f, format: "%.0f");
6701 ImGui::SliderFloat(label: "PopupBorderSize", v: &style.PopupBorderSize, v_min: 0.0f, v_max: 1.0f, format: "%.0f");
6702 ImGui::SliderFloat(label: "FrameBorderSize", v: &style.FrameBorderSize, v_min: 0.0f, v_max: 1.0f, format: "%.0f");
6703 ImGui::SliderFloat(label: "TabBorderSize", v: &style.TabBorderSize, v_min: 0.0f, v_max: 1.0f, format: "%.0f");
6704 ImGui::SliderFloat(label: "TabBarBorderSize", v: &style.TabBarBorderSize, v_min: 0.0f, v_max: 2.0f, format: "%.0f");
6705
6706 ImGui::SeparatorText(label: "Rounding");
6707 ImGui::SliderFloat(label: "WindowRounding", v: &style.WindowRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6708 ImGui::SliderFloat(label: "ChildRounding", v: &style.ChildRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6709 ImGui::SliderFloat(label: "FrameRounding", v: &style.FrameRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6710 ImGui::SliderFloat(label: "PopupRounding", v: &style.PopupRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6711 ImGui::SliderFloat(label: "ScrollbarRounding", v: &style.ScrollbarRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6712 ImGui::SliderFloat(label: "GrabRounding", v: &style.GrabRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6713 ImGui::SliderFloat(label: "TabRounding", v: &style.TabRounding, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6714
6715 ImGui::SeparatorText(label: "Tables");
6716 ImGui::SliderFloat2(label: "CellPadding", v: (float*)&style.CellPadding, v_min: 0.0f, v_max: 20.0f, format: "%.0f");
6717 ImGui::SliderAngle(label: "TableAngledHeadersAngle", v_rad: &style.TableAngledHeadersAngle, v_degrees_min: -50.0f, v_degrees_max: +50.0f);
6718
6719 ImGui::SeparatorText(label: "Widgets");
6720 ImGui::SliderFloat2(label: "WindowTitleAlign", v: (float*)&style.WindowTitleAlign, v_min: 0.0f, v_max: 1.0f, format: "%.2f");
6721 int window_menu_button_position = style.WindowMenuButtonPosition + 1;
6722 if (ImGui::Combo(label: "WindowMenuButtonPosition", current_item: (int*)&window_menu_button_position, items_separated_by_zeros: "None\0Left\0Right\0"))
6723 style.WindowMenuButtonPosition = window_menu_button_position - 1;
6724 ImGui::Combo(label: "ColorButtonPosition", current_item: (int*)&style.ColorButtonPosition, items_separated_by_zeros: "Left\0Right\0");
6725 ImGui::SliderFloat2(label: "ButtonTextAlign", v: (float*)&style.ButtonTextAlign, v_min: 0.0f, v_max: 1.0f, format: "%.2f");
6726 ImGui::SameLine(); HelpMarker(desc: "Alignment applies when a button is larger than its text content.");
6727 ImGui::SliderFloat2(label: "SelectableTextAlign", v: (float*)&style.SelectableTextAlign, v_min: 0.0f, v_max: 1.0f, format: "%.2f");
6728 ImGui::SameLine(); HelpMarker(desc: "Alignment applies when a selectable is larger than its text content.");
6729 ImGui::SliderFloat(label: "SeparatorTextBorderSize", v: &style.SeparatorTextBorderSize, v_min: 0.0f, v_max: 10.0f, format: "%.0f");
6730 ImGui::SliderFloat2(label: "SeparatorTextAlign", v: (float*)&style.SeparatorTextAlign, v_min: 0.0f, v_max: 1.0f, format: "%.2f");
6731 ImGui::SliderFloat2(label: "SeparatorTextPadding", v: (float*)&style.SeparatorTextPadding, v_min: 0.0f, v_max: 40.0f, format: "%.0f");
6732 ImGui::SliderFloat(label: "LogSliderDeadzone", v: &style.LogSliderDeadzone, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6733
6734 ImGui::SeparatorText(label: "Docking");
6735 ImGui::SliderFloat(label: "DockingSplitterSize", v: &style.DockingSeparatorSize, v_min: 0.0f, v_max: 12.0f, format: "%.0f");
6736
6737 ImGui::SeparatorText(label: "Tooltips");
6738 for (int n = 0; n < 2; n++)
6739 if (ImGui::TreeNodeEx(label: n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
6740 {
6741 ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
6742 ImGui::CheckboxFlags(label: "ImGuiHoveredFlags_DelayNone", flags: p, flags_value: ImGuiHoveredFlags_DelayNone);
6743 ImGui::CheckboxFlags(label: "ImGuiHoveredFlags_DelayShort", flags: p, flags_value: ImGuiHoveredFlags_DelayShort);
6744 ImGui::CheckboxFlags(label: "ImGuiHoveredFlags_DelayNormal", flags: p, flags_value: ImGuiHoveredFlags_DelayNormal);
6745 ImGui::CheckboxFlags(label: "ImGuiHoveredFlags_Stationary", flags: p, flags_value: ImGuiHoveredFlags_Stationary);
6746 ImGui::CheckboxFlags(label: "ImGuiHoveredFlags_NoSharedDelay", flags: p, flags_value: ImGuiHoveredFlags_NoSharedDelay);
6747 ImGui::TreePop();
6748 }
6749
6750 ImGui::SeparatorText(label: "Misc");
6751 ImGui::SliderFloat2(label: "DisplaySafeAreaPadding", v: (float*)&style.DisplaySafeAreaPadding, v_min: 0.0f, v_max: 30.0f, format: "%.0f"); ImGui::SameLine(); HelpMarker(desc: "Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
6752
6753 ImGui::EndTabItem();
6754 }
6755
6756 if (ImGui::BeginTabItem(label: "Colors"))
6757 {
6758 static int output_dest = 0;
6759 static bool output_only_modified = true;
6760 if (ImGui::Button(label: "Export"))
6761 {
6762 if (output_dest == 0)
6763 ImGui::LogToClipboard();
6764 else
6765 ImGui::LogToTTY();
6766 ImGui::LogText(fmt: "ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
6767 for (int i = 0; i < ImGuiCol_COUNT; i++)
6768 {
6769 const ImVec4& col = style.Colors[i];
6770 const char* name = ImGui::GetStyleColorName(idx: i);
6771 if (!output_only_modified || memcmp(s1: &col, s2: &ref->Colors[i], n: sizeof(ImVec4)) != 0)
6772 ImGui::LogText(fmt: "colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
6773 name, 23 - (int)strlen(s: name), "", col.x, col.y, col.z, col.w);
6774 }
6775 ImGui::LogFinish();
6776 }
6777 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo(label: "##output_type", current_item: &output_dest, items_separated_by_zeros: "To Clipboard\0To TTY\0");
6778 ImGui::SameLine(); ImGui::Checkbox(label: "Only Modified Colors", v: &output_only_modified);
6779
6780 static ImGuiTextFilter filter;
6781 filter.Draw(label: "Filter colors", width: ImGui::GetFontSize() * 16);
6782
6783 static ImGuiColorEditFlags alpha_flags = 0;
6784 if (ImGui::RadioButton(label: "Opaque", active: alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
6785 if (ImGui::RadioButton(label: "Alpha", active: alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
6786 if (ImGui::RadioButton(label: "Both", active: alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
6787 HelpMarker(
6788 desc: "In the color list:\n"
6789 "Left-click on color square to open color picker,\n"
6790 "Right-click to open edit options menu.");
6791
6792 ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), size_max: ImVec2(FLT_MAX, FLT_MAX));
6793 ImGui::BeginChild(str_id: "##colors", size: ImVec2(0, 0), child_flags: ImGuiChildFlags_Border, window_flags: ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
6794 ImGui::PushItemWidth(item_width: ImGui::GetFontSize() * -12);
6795 for (int i = 0; i < ImGuiCol_COUNT; i++)
6796 {
6797 const char* name = ImGui::GetStyleColorName(idx: i);
6798 if (!filter.PassFilter(text: name))
6799 continue;
6800 ImGui::PushID(int_id: i);
6801#ifndef IMGUI_DISABLE_DEBUG_TOOLS
6802 if (ImGui::Button(label: "?"))
6803 ImGui::DebugFlashStyleColor(idx: (ImGuiCol)i);
6804 ImGui::SetItemTooltip("Flash given color to identify places where it is used.");
6805 ImGui::SameLine();
6806#endif
6807 ImGui::ColorEdit4(label: "##color", col: (float*)&style.Colors[i], flags: ImGuiColorEditFlags_AlphaBar | alpha_flags);
6808 if (memcmp(s1: &style.Colors[i], s2: &ref->Colors[i], n: sizeof(ImVec4)) != 0)
6809 {
6810 // Tips: in a real user application, you may want to merge and use an icon font into the main font,
6811 // so instead of "Save"/"Revert" you'd use icons!
6812 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
6813 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: style.ItemInnerSpacing.x); if (ImGui::Button(label: "Save")) { ref->Colors[i] = style.Colors[i]; }
6814 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: style.ItemInnerSpacing.x); if (ImGui::Button(label: "Revert")) { style.Colors[i] = ref->Colors[i]; }
6815 }
6816 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: style.ItemInnerSpacing.x);
6817 ImGui::TextUnformatted(text: name);
6818 ImGui::PopID();
6819 }
6820 ImGui::PopItemWidth();
6821 ImGui::EndChild();
6822
6823 ImGui::EndTabItem();
6824 }
6825
6826 if (ImGui::BeginTabItem(label: "Fonts"))
6827 {
6828 ImGuiIO& io = ImGui::GetIO();
6829 ImFontAtlas* atlas = io.Fonts;
6830 HelpMarker(desc: "Read FAQ and docs/FONTS.md for details on font loading.");
6831 ImGui::ShowFontAtlas(atlas);
6832
6833 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
6834 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
6835 const float MIN_SCALE = 0.3f;
6836 const float MAX_SCALE = 2.0f;
6837 HelpMarker(
6838 desc: "Those are old settings provided for convenience.\n"
6839 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
6840 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
6841 "Using those settings here will give you poor quality results.");
6842 static float window_scale = 1.0f;
6843 ImGui::PushItemWidth(item_width: ImGui::GetFontSize() * 8);
6844 if (ImGui::DragFloat(label: "window scale", v: &window_scale, v_speed: 0.005f, v_min: MIN_SCALE, v_max: MAX_SCALE, format: "%.2f", flags: ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
6845 ImGui::SetWindowFontScale(window_scale);
6846 ImGui::DragFloat(label: "global scale", v: &io.FontGlobalScale, v_speed: 0.005f, v_min: MIN_SCALE, v_max: MAX_SCALE, format: "%.2f", flags: ImGuiSliderFlags_AlwaysClamp); // Scale everything
6847 ImGui::PopItemWidth();
6848
6849 ImGui::EndTabItem();
6850 }
6851
6852 if (ImGui::BeginTabItem(label: "Rendering"))
6853 {
6854 ImGui::Checkbox(label: "Anti-aliased lines", v: &style.AntiAliasedLines);
6855 ImGui::SameLine();
6856 HelpMarker(desc: "When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
6857
6858 ImGui::Checkbox(label: "Anti-aliased lines use texture", v: &style.AntiAliasedLinesUseTex);
6859 ImGui::SameLine();
6860 HelpMarker(desc: "Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
6861
6862 ImGui::Checkbox(label: "Anti-aliased fill", v: &style.AntiAliasedFill);
6863 ImGui::PushItemWidth(item_width: ImGui::GetFontSize() * 8);
6864 ImGui::DragFloat(label: "Curve Tessellation Tolerance", v: &style.CurveTessellationTol, v_speed: 0.02f, v_min: 0.10f, v_max: 10.0f, format: "%.2f");
6865 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
6866
6867 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
6868 ImGui::DragFloat(label: "Circle Tessellation Max Error", v: &style.CircleTessellationMaxError , v_speed: 0.005f, v_min: 0.10f, v_max: 5.0f, format: "%.2f", flags: ImGuiSliderFlags_AlwaysClamp);
6869 const bool show_samples = ImGui::IsItemActive();
6870 if (show_samples)
6871 ImGui::SetNextWindowPos(pos: ImGui::GetCursorScreenPos());
6872 if (show_samples && ImGui::BeginTooltip())
6873 {
6874 ImGui::TextUnformatted(text: "(R = radius, N = number of segments)");
6875 ImGui::Spacing();
6876 ImDrawList* draw_list = ImGui::GetWindowDrawList();
6877 const float min_widget_width = ImGui::CalcTextSize(text: "N: MMM\nR: MMM").x;
6878 for (int n = 0; n < 8; n++)
6879 {
6880 const float RAD_MIN = 5.0f;
6881 const float RAD_MAX = 70.0f;
6882 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
6883
6884 ImGui::BeginGroup();
6885
6886 ImGui::Text(fmt: "R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(radius: rad));
6887
6888 const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
6889 const float offset_x = floorf(x: canvas_width * 0.5f);
6890 const float offset_y = floorf(x: RAD_MAX);
6891
6892 const ImVec2 p1 = ImGui::GetCursorScreenPos();
6893 draw_list->AddCircle(center: ImVec2(p1.x + offset_x, p1.y + offset_y), radius: rad, col: ImGui::GetColorU32(idx: ImGuiCol_Text));
6894 ImGui::Dummy(size: ImVec2(canvas_width, RAD_MAX * 2));
6895
6896 /*
6897 const ImVec2 p2 = ImGui::GetCursorScreenPos();
6898 draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
6899 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
6900 */
6901
6902 ImGui::EndGroup();
6903 ImGui::SameLine();
6904 }
6905 ImGui::EndTooltip();
6906 }
6907 ImGui::SameLine();
6908 HelpMarker(desc: "When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
6909
6910 ImGui::DragFloat(label: "Global Alpha", v: &style.Alpha, v_speed: 0.005f, v_min: 0.20f, v_max: 1.0f, format: "%.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.
6911 ImGui::DragFloat(label: "Disabled Alpha", v: &style.DisabledAlpha, v_speed: 0.005f, v_min: 0.0f, v_max: 1.0f, format: "%.2f"); ImGui::SameLine(); HelpMarker(desc: "Additional alpha multiplier for disabled items (multiply over current value of Alpha).");
6912 ImGui::PopItemWidth();
6913
6914 ImGui::EndTabItem();
6915 }
6916
6917 ImGui::EndTabBar();
6918 }
6919
6920 ImGui::PopItemWidth();
6921}
6922
6923//-----------------------------------------------------------------------------
6924// [SECTION] User Guide / ShowUserGuide()
6925//-----------------------------------------------------------------------------
6926
6927void ImGui::ShowUserGuide()
6928{
6929 ImGuiIO& io = ImGui::GetIO();
6930 ImGui::BulletText(fmt: "Double-click on title bar to collapse window.");
6931 ImGui::BulletText(
6932 fmt: "Click and drag on lower corner to resize window\n"
6933 "(double-click to auto fit window to its contents).");
6934 ImGui::BulletText(fmt: "CTRL+Click on a slider or drag box to input value as text.");
6935 ImGui::BulletText(fmt: "TAB/SHIFT+TAB to cycle through keyboard editable fields.");
6936 ImGui::BulletText(fmt: "CTRL+Tab to select a window.");
6937 if (io.FontAllowUserScaling)
6938 ImGui::BulletText(fmt: "CTRL+Mouse Wheel to zoom window contents.");
6939 ImGui::BulletText(fmt: "While inputing text:\n");
6940 ImGui::Indent();
6941 ImGui::BulletText(fmt: "CTRL+Left/Right to word jump.");
6942 ImGui::BulletText(fmt: "CTRL+A or double-click to select all.");
6943 ImGui::BulletText(fmt: "CTRL+X/C/V to use clipboard cut/copy/paste.");
6944 ImGui::BulletText(fmt: "CTRL+Z,CTRL+Y to undo/redo.");
6945 ImGui::BulletText(fmt: "ESCAPE to revert.");
6946 ImGui::Unindent();
6947 ImGui::BulletText(fmt: "With keyboard navigation enabled:");
6948 ImGui::Indent();
6949 ImGui::BulletText(fmt: "Arrow keys to navigate.");
6950 ImGui::BulletText(fmt: "Space to activate a widget.");
6951 ImGui::BulletText(fmt: "Return to input text into a widget.");
6952 ImGui::BulletText(fmt: "Escape to deactivate a widget, close popup, exit child window.");
6953 ImGui::BulletText(fmt: "Alt to jump to the menu layer of a window.");
6954 ImGui::Unindent();
6955}
6956
6957//-----------------------------------------------------------------------------
6958// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
6959//-----------------------------------------------------------------------------
6960// - ShowExampleAppMainMenuBar()
6961// - ShowExampleMenuFile()
6962//-----------------------------------------------------------------------------
6963
6964// Demonstrate creating a "main" fullscreen menu bar and populating it.
6965// Note the difference between BeginMainMenuBar() and BeginMenuBar():
6966// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
6967// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
6968static void ShowExampleAppMainMenuBar()
6969{
6970 if (ImGui::BeginMainMenuBar())
6971 {
6972 if (ImGui::BeginMenu(label: "File"))
6973 {
6974 ShowExampleMenuFile();
6975 ImGui::EndMenu();
6976 }
6977 if (ImGui::BeginMenu(label: "Edit"))
6978 {
6979 if (ImGui::MenuItem(label: "Undo", shortcut: "CTRL+Z")) {}
6980 if (ImGui::MenuItem(label: "Redo", shortcut: "CTRL+Y", selected: false, enabled: false)) {} // Disabled item
6981 ImGui::Separator();
6982 if (ImGui::MenuItem(label: "Cut", shortcut: "CTRL+X")) {}
6983 if (ImGui::MenuItem(label: "Copy", shortcut: "CTRL+C")) {}
6984 if (ImGui::MenuItem(label: "Paste", shortcut: "CTRL+V")) {}
6985 ImGui::EndMenu();
6986 }
6987 ImGui::EndMainMenuBar();
6988 }
6989}
6990
6991// Note that shortcuts are currently provided for display only
6992// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
6993static void ShowExampleMenuFile()
6994{
6995 IMGUI_DEMO_MARKER("Examples/Menu");
6996 ImGui::MenuItem(label: "(demo menu)", NULL, selected: false, enabled: false);
6997 if (ImGui::MenuItem(label: "New")) {}
6998 if (ImGui::MenuItem(label: "Open", shortcut: "Ctrl+O")) {}
6999 if (ImGui::BeginMenu(label: "Open Recent"))
7000 {
7001 ImGui::MenuItem(label: "fish_hat.c");
7002 ImGui::MenuItem(label: "fish_hat.inl");
7003 ImGui::MenuItem(label: "fish_hat.h");
7004 if (ImGui::BeginMenu(label: "More.."))
7005 {
7006 ImGui::MenuItem(label: "Hello");
7007 ImGui::MenuItem(label: "Sailor");
7008 if (ImGui::BeginMenu(label: "Recurse.."))
7009 {
7010 ShowExampleMenuFile();
7011 ImGui::EndMenu();
7012 }
7013 ImGui::EndMenu();
7014 }
7015 ImGui::EndMenu();
7016 }
7017 if (ImGui::MenuItem(label: "Save", shortcut: "Ctrl+S")) {}
7018 if (ImGui::MenuItem(label: "Save As..")) {}
7019
7020 ImGui::Separator();
7021 IMGUI_DEMO_MARKER("Examples/Menu/Options");
7022 if (ImGui::BeginMenu(label: "Options"))
7023 {
7024 static bool enabled = true;
7025 ImGui::MenuItem(label: "Enabled", shortcut: "", p_selected: &enabled);
7026 ImGui::BeginChild(str_id: "child", size: ImVec2(0, 60), child_flags: ImGuiChildFlags_Border);
7027 for (int i = 0; i < 10; i++)
7028 ImGui::Text(fmt: "Scrolling Text %d", i);
7029 ImGui::EndChild();
7030 static float f = 0.5f;
7031 static int n = 0;
7032 ImGui::SliderFloat(label: "Value", v: &f, v_min: 0.0f, v_max: 1.0f);
7033 ImGui::InputFloat(label: "Input", v: &f, step: 0.1f);
7034 ImGui::Combo(label: "Combo", current_item: &n, items_separated_by_zeros: "Yes\0No\0Maybe\0\0");
7035 ImGui::EndMenu();
7036 }
7037
7038 IMGUI_DEMO_MARKER("Examples/Menu/Colors");
7039 if (ImGui::BeginMenu(label: "Colors"))
7040 {
7041 float sz = ImGui::GetTextLineHeight();
7042 for (int i = 0; i < ImGuiCol_COUNT; i++)
7043 {
7044 const char* name = ImGui::GetStyleColorName(idx: (ImGuiCol)i);
7045 ImVec2 p = ImGui::GetCursorScreenPos();
7046 ImGui::GetWindowDrawList()->AddRectFilled(p_min: p, p_max: ImVec2(p.x + sz, p.y + sz), col: ImGui::GetColorU32(idx: (ImGuiCol)i));
7047 ImGui::Dummy(size: ImVec2(sz, sz));
7048 ImGui::SameLine();
7049 ImGui::MenuItem(label: name);
7050 }
7051 ImGui::EndMenu();
7052 }
7053
7054 // Here we demonstrate appending again to the "Options" menu (which we already created above)
7055 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
7056 // In a real code-base using it would make senses to use this feature from very different code locations.
7057 if (ImGui::BeginMenu(label: "Options")) // <-- Append!
7058 {
7059 IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
7060 static bool b = true;
7061 ImGui::Checkbox(label: "SomeOption", v: &b);
7062 ImGui::EndMenu();
7063 }
7064
7065 if (ImGui::BeginMenu(label: "Disabled", enabled: false)) // Disabled
7066 {
7067 IM_ASSERT(0);
7068 }
7069 if (ImGui::MenuItem(label: "Checked", NULL, selected: true)) {}
7070 ImGui::Separator();
7071 if (ImGui::MenuItem(label: "Quit", shortcut: "Alt+F4")) {}
7072}
7073
7074//-----------------------------------------------------------------------------
7075// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
7076//-----------------------------------------------------------------------------
7077
7078// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
7079// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
7080struct ExampleAppConsole
7081{
7082 char InputBuf[256];
7083 ImVector<char*> Items;
7084 ImVector<const char*> Commands;
7085 ImVector<char*> History;
7086 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
7087 ImGuiTextFilter Filter;
7088 bool AutoScroll;
7089 bool ScrollToBottom;
7090
7091 ExampleAppConsole()
7092 {
7093 IMGUI_DEMO_MARKER("Examples/Console");
7094 ClearLog();
7095 memset(s: InputBuf, c: 0, n: sizeof(InputBuf));
7096 HistoryPos = -1;
7097
7098 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
7099 Commands.push_back(v: "HELP");
7100 Commands.push_back(v: "HISTORY");
7101 Commands.push_back(v: "CLEAR");
7102 Commands.push_back(v: "CLASSIFY");
7103 AutoScroll = true;
7104 ScrollToBottom = false;
7105 AddLog(fmt: "Welcome to Dear ImGui!");
7106 }
7107 ~ExampleAppConsole()
7108 {
7109 ClearLog();
7110 for (int i = 0; i < History.Size; i++)
7111 ImGui::MemFree(ptr: History[i]);
7112 }
7113
7114 // Portable helpers
7115 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(c: *s2) - toupper(c: *s1)) == 0 && *s1) { s1++; s2++; } return d; }
7116 static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(c: *s2) - toupper(c: *s1)) == 0 && *s1) { s1++; s2++; n--; } return d; }
7117 static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s: s) + 1; void* buf = ImGui::MemAlloc(size: len); IM_ASSERT(buf); return (char*)memcpy(dest: buf, src: (const void*)s, n: len); }
7118 static void Strtrim(char* s) { char* str_end = s + strlen(s: s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
7119
7120 void ClearLog()
7121 {
7122 for (int i = 0; i < Items.Size; i++)
7123 ImGui::MemFree(ptr: Items[i]);
7124 Items.clear();
7125 }
7126
7127 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
7128 {
7129 // FIXME-OPT
7130 char buf[1024];
7131 va_list args;
7132 va_start(args, fmt);
7133 vsnprintf(s: buf, IM_ARRAYSIZE(buf), format: fmt, arg: args);
7134 buf[IM_ARRAYSIZE(buf)-1] = 0;
7135 va_end(args);
7136 Items.push_back(v: Strdup(s: buf));
7137 }
7138
7139 void Draw(const char* title, bool* p_open)
7140 {
7141 ImGui::SetNextWindowSize(size: ImVec2(520, 600), cond: ImGuiCond_FirstUseEver);
7142 if (!ImGui::Begin(name: title, p_open))
7143 {
7144 ImGui::End();
7145 return;
7146 }
7147
7148 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
7149 // So e.g. IsItemHovered() will return true when hovering the title bar.
7150 // Here we create a context menu only available from the title bar.
7151 if (ImGui::BeginPopupContextItem())
7152 {
7153 if (ImGui::MenuItem(label: "Close Console"))
7154 *p_open = false;
7155 ImGui::EndPopup();
7156 }
7157
7158 ImGui::TextWrapped(
7159 fmt: "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
7160 "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
7161 ImGui::TextWrapped(fmt: "Enter 'HELP' for help.");
7162
7163 // TODO: display items starting from the bottom
7164
7165 if (ImGui::SmallButton(label: "Add Debug Text")) { AddLog(fmt: "%d some text", Items.Size); AddLog(fmt: "some more text"); AddLog(fmt: "display very important message here!"); }
7166 ImGui::SameLine();
7167 if (ImGui::SmallButton(label: "Add Debug Error")) { AddLog(fmt: "[error] something went wrong"); }
7168 ImGui::SameLine();
7169 if (ImGui::SmallButton(label: "Clear")) { ClearLog(); }
7170 ImGui::SameLine();
7171 bool copy_to_clipboard = ImGui::SmallButton(label: "Copy");
7172 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
7173
7174 ImGui::Separator();
7175
7176 // Options menu
7177 if (ImGui::BeginPopup(str_id: "Options"))
7178 {
7179 ImGui::Checkbox(label: "Auto-scroll", v: &AutoScroll);
7180 ImGui::EndPopup();
7181 }
7182
7183 // Options, Filter
7184 if (ImGui::Button(label: "Options"))
7185 ImGui::OpenPopup(str_id: "Options");
7186 ImGui::SameLine();
7187 Filter.Draw(label: "Filter (\"incl,-excl\") (\"error\")", width: 180);
7188 ImGui::Separator();
7189
7190 // Reserve enough left-over height for 1 separator + 1 input text
7191 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
7192 if (ImGui::BeginChild(str_id: "ScrollingRegion", size: ImVec2(0, -footer_height_to_reserve), child_flags: ImGuiChildFlags_None, window_flags: ImGuiWindowFlags_HorizontalScrollbar))
7193 {
7194 if (ImGui::BeginPopupContextWindow())
7195 {
7196 if (ImGui::Selectable(label: "Clear")) ClearLog();
7197 ImGui::EndPopup();
7198 }
7199
7200 // Display every line as a separate entry so we can change their color or add custom widgets.
7201 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
7202 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
7203 // to only process visible items. The clipper will automatically measure the height of your first item and then
7204 // "seek" to display only items in the visible area.
7205 // To use the clipper we can replace your standard loop:
7206 // for (int i = 0; i < Items.Size; i++)
7207 // With:
7208 // ImGuiListClipper clipper;
7209 // clipper.Begin(Items.Size);
7210 // while (clipper.Step())
7211 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7212 // - That your items are evenly spaced (same height)
7213 // - That you have cheap random access to your elements (you can access them given their index,
7214 // without processing all the ones before)
7215 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
7216 // We would need random-access on the post-filtered list.
7217 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
7218 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
7219 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
7220 // to improve this example code!
7221 // If your items are of variable height:
7222 // - Split them into same height items would be simpler and facilitate random-seeking into your list.
7223 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
7224 ImGui::PushStyleVar(idx: ImGuiStyleVar_ItemSpacing, val: ImVec2(4, 1)); // Tighten spacing
7225 if (copy_to_clipboard)
7226 ImGui::LogToClipboard();
7227 for (const char* item : Items)
7228 {
7229 if (!Filter.PassFilter(text: item))
7230 continue;
7231
7232 // Normally you would store more information in your item than just a string.
7233 // (e.g. make Items[] an array of structure, store color/type etc.)
7234 ImVec4 color;
7235 bool has_color = false;
7236 if (strstr(haystack: item, needle: "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
7237 else if (strncmp(s1: item, s2: "# ", n: 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
7238 if (has_color)
7239 ImGui::PushStyleColor(idx: ImGuiCol_Text, col: color);
7240 ImGui::TextUnformatted(text: item);
7241 if (has_color)
7242 ImGui::PopStyleColor();
7243 }
7244 if (copy_to_clipboard)
7245 ImGui::LogFinish();
7246
7247 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
7248 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
7249 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
7250 ImGui::SetScrollHereY(1.0f);
7251 ScrollToBottom = false;
7252
7253 ImGui::PopStyleVar();
7254 }
7255 ImGui::EndChild();
7256 ImGui::Separator();
7257
7258 // Command-line
7259 bool reclaim_focus = false;
7260 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
7261 if (ImGui::InputText(label: "Input", buf: InputBuf, IM_ARRAYSIZE(InputBuf), flags: input_text_flags, callback: &TextEditCallbackStub, user_data: (void*)this))
7262 {
7263 char* s = InputBuf;
7264 Strtrim(s);
7265 if (s[0])
7266 ExecCommand(command_line: s);
7267 strcpy(dest: s, src: "");
7268 reclaim_focus = true;
7269 }
7270
7271 // Auto-focus on window apparition
7272 ImGui::SetItemDefaultFocus();
7273 if (reclaim_focus)
7274 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
7275
7276 ImGui::End();
7277 }
7278
7279 void ExecCommand(const char* command_line)
7280 {
7281 AddLog(fmt: "# %s\n", command_line);
7282
7283 // Insert into history. First find match and delete it so it can be pushed to the back.
7284 // This isn't trying to be smart or optimal.
7285 HistoryPos = -1;
7286 for (int i = History.Size - 1; i >= 0; i--)
7287 if (Stricmp(s1: History[i], s2: command_line) == 0)
7288 {
7289 ImGui::MemFree(ptr: History[i]);
7290 History.erase(it: History.begin() + i);
7291 break;
7292 }
7293 History.push_back(v: Strdup(s: command_line));
7294
7295 // Process command
7296 if (Stricmp(s1: command_line, s2: "CLEAR") == 0)
7297 {
7298 ClearLog();
7299 }
7300 else if (Stricmp(s1: command_line, s2: "HELP") == 0)
7301 {
7302 AddLog(fmt: "Commands:");
7303 for (int i = 0; i < Commands.Size; i++)
7304 AddLog(fmt: "- %s", Commands[i]);
7305 }
7306 else if (Stricmp(s1: command_line, s2: "HISTORY") == 0)
7307 {
7308 int first = History.Size - 10;
7309 for (int i = first > 0 ? first : 0; i < History.Size; i++)
7310 AddLog(fmt: "%3d: %s\n", i, History[i]);
7311 }
7312 else
7313 {
7314 AddLog(fmt: "Unknown command: '%s'\n", command_line);
7315 }
7316
7317 // On command input, we scroll to bottom even if AutoScroll==false
7318 ScrollToBottom = true;
7319 }
7320
7321 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
7322 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
7323 {
7324 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
7325 return console->TextEditCallback(data);
7326 }
7327
7328 int TextEditCallback(ImGuiInputTextCallbackData* data)
7329 {
7330 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
7331 switch (data->EventFlag)
7332 {
7333 case ImGuiInputTextFlags_CallbackCompletion:
7334 {
7335 // Example of TEXT COMPLETION
7336
7337 // Locate beginning of current word
7338 const char* word_end = data->Buf + data->CursorPos;
7339 const char* word_start = word_end;
7340 while (word_start > data->Buf)
7341 {
7342 const char c = word_start[-1];
7343 if (c == ' ' || c == '\t' || c == ',' || c == ';')
7344 break;
7345 word_start--;
7346 }
7347
7348 // Build a list of candidates
7349 ImVector<const char*> candidates;
7350 for (int i = 0; i < Commands.Size; i++)
7351 if (Strnicmp(s1: Commands[i], s2: word_start, n: (int)(word_end - word_start)) == 0)
7352 candidates.push_back(v: Commands[i]);
7353
7354 if (candidates.Size == 0)
7355 {
7356 // No match
7357 AddLog(fmt: "No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
7358 }
7359 else if (candidates.Size == 1)
7360 {
7361 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
7362 data->DeleteChars(pos: (int)(word_start - data->Buf), bytes_count: (int)(word_end - word_start));
7363 data->InsertChars(pos: data->CursorPos, text: candidates[0]);
7364 data->InsertChars(pos: data->CursorPos, text: " ");
7365 }
7366 else
7367 {
7368 // Multiple matches. Complete as much as we can..
7369 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
7370 int match_len = (int)(word_end - word_start);
7371 for (;;)
7372 {
7373 int c = 0;
7374 bool all_candidates_matches = true;
7375 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
7376 if (i == 0)
7377 c = toupper(c: candidates[i][match_len]);
7378 else if (c == 0 || c != toupper(c: candidates[i][match_len]))
7379 all_candidates_matches = false;
7380 if (!all_candidates_matches)
7381 break;
7382 match_len++;
7383 }
7384
7385 if (match_len > 0)
7386 {
7387 data->DeleteChars(pos: (int)(word_start - data->Buf), bytes_count: (int)(word_end - word_start));
7388 data->InsertChars(pos: data->CursorPos, text: candidates[0], text_end: candidates[0] + match_len);
7389 }
7390
7391 // List matches
7392 AddLog(fmt: "Possible matches:\n");
7393 for (int i = 0; i < candidates.Size; i++)
7394 AddLog(fmt: "- %s\n", candidates[i]);
7395 }
7396
7397 break;
7398 }
7399 case ImGuiInputTextFlags_CallbackHistory:
7400 {
7401 // Example of HISTORY
7402 const int prev_history_pos = HistoryPos;
7403 if (data->EventKey == ImGuiKey_UpArrow)
7404 {
7405 if (HistoryPos == -1)
7406 HistoryPos = History.Size - 1;
7407 else if (HistoryPos > 0)
7408 HistoryPos--;
7409 }
7410 else if (data->EventKey == ImGuiKey_DownArrow)
7411 {
7412 if (HistoryPos != -1)
7413 if (++HistoryPos >= History.Size)
7414 HistoryPos = -1;
7415 }
7416
7417 // A better implementation would preserve the data on the current input line along with cursor position.
7418 if (prev_history_pos != HistoryPos)
7419 {
7420 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
7421 data->DeleteChars(pos: 0, bytes_count: data->BufTextLen);
7422 data->InsertChars(pos: 0, text: history_str);
7423 }
7424 }
7425 }
7426 return 0;
7427 }
7428};
7429
7430static void ShowExampleAppConsole(bool* p_open)
7431{
7432 static ExampleAppConsole console;
7433 console.Draw(title: "Example: Console", p_open);
7434}
7435
7436//-----------------------------------------------------------------------------
7437// [SECTION] Example App: Debug Log / ShowExampleAppLog()
7438//-----------------------------------------------------------------------------
7439
7440// Usage:
7441// static ExampleAppLog my_log;
7442// my_log.AddLog("Hello %d world\n", 123);
7443// my_log.Draw("title");
7444struct ExampleAppLog
7445{
7446 ImGuiTextBuffer Buf;
7447 ImGuiTextFilter Filter;
7448 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
7449 bool AutoScroll; // Keep scrolling if already at the bottom.
7450
7451 ExampleAppLog()
7452 {
7453 AutoScroll = true;
7454 Clear();
7455 }
7456
7457 void Clear()
7458 {
7459 Buf.clear();
7460 LineOffsets.clear();
7461 LineOffsets.push_back(v: 0);
7462 }
7463
7464 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
7465 {
7466 int old_size = Buf.size();
7467 va_list args;
7468 va_start(args, fmt);
7469 Buf.appendfv(fmt, args);
7470 va_end(args);
7471 for (int new_size = Buf.size(); old_size < new_size; old_size++)
7472 if (Buf[old_size] == '\n')
7473 LineOffsets.push_back(v: old_size + 1);
7474 }
7475
7476 void Draw(const char* title, bool* p_open = NULL)
7477 {
7478 if (!ImGui::Begin(name: title, p_open))
7479 {
7480 ImGui::End();
7481 return;
7482 }
7483
7484 // Options menu
7485 if (ImGui::BeginPopup(str_id: "Options"))
7486 {
7487 ImGui::Checkbox(label: "Auto-scroll", v: &AutoScroll);
7488 ImGui::EndPopup();
7489 }
7490
7491 // Main window
7492 if (ImGui::Button(label: "Options"))
7493 ImGui::OpenPopup(str_id: "Options");
7494 ImGui::SameLine();
7495 bool clear = ImGui::Button(label: "Clear");
7496 ImGui::SameLine();
7497 bool copy = ImGui::Button(label: "Copy");
7498 ImGui::SameLine();
7499 Filter.Draw(label: "Filter", width: -100.0f);
7500
7501 ImGui::Separator();
7502
7503 if (ImGui::BeginChild(str_id: "scrolling", size: ImVec2(0, 0), child_flags: ImGuiChildFlags_None, window_flags: ImGuiWindowFlags_HorizontalScrollbar))
7504 {
7505 if (clear)
7506 Clear();
7507 if (copy)
7508 ImGui::LogToClipboard();
7509
7510 ImGui::PushStyleVar(idx: ImGuiStyleVar_ItemSpacing, val: ImVec2(0, 0));
7511 const char* buf = Buf.begin();
7512 const char* buf_end = Buf.end();
7513 if (Filter.IsActive())
7514 {
7515 // In this example we don't use the clipper when Filter is enabled.
7516 // This is because we don't have random access to the result of our filter.
7517 // A real application processing logs with ten of thousands of entries may want to store the result of
7518 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
7519 for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
7520 {
7521 const char* line_start = buf + LineOffsets[line_no];
7522 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
7523 if (Filter.PassFilter(text: line_start, text_end: line_end))
7524 ImGui::TextUnformatted(text: line_start, text_end: line_end);
7525 }
7526 }
7527 else
7528 {
7529 // The simplest and easy way to display the entire buffer:
7530 // ImGui::TextUnformatted(buf_begin, buf_end);
7531 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
7532 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
7533 // within the visible area.
7534 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
7535 // on your side is recommended. Using ImGuiListClipper requires
7536 // - A) random access into your data
7537 // - B) items all being the same height,
7538 // both of which we can handle since we have an array pointing to the beginning of each line of text.
7539 // When using the filter (in the block of code above) we don't have random access into the data to display
7540 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
7541 // it possible (and would be recommended if you want to search through tens of thousands of entries).
7542 ImGuiListClipper clipper;
7543 clipper.Begin(items_count: LineOffsets.Size);
7544 while (clipper.Step())
7545 {
7546 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
7547 {
7548 const char* line_start = buf + LineOffsets[line_no];
7549 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
7550 ImGui::TextUnformatted(text: line_start, text_end: line_end);
7551 }
7552 }
7553 clipper.End();
7554 }
7555 ImGui::PopStyleVar();
7556
7557 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
7558 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
7559 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
7560 ImGui::SetScrollHereY(1.0f);
7561 }
7562 ImGui::EndChild();
7563 ImGui::End();
7564 }
7565};
7566
7567// Demonstrate creating a simple log window with basic filtering.
7568static void ShowExampleAppLog(bool* p_open)
7569{
7570 static ExampleAppLog log;
7571
7572 // For the demo: add a debug button _BEFORE_ the normal log window contents
7573 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
7574 // Most of the contents of the window will be added by the log.Draw() call.
7575 ImGui::SetNextWindowSize(size: ImVec2(500, 400), cond: ImGuiCond_FirstUseEver);
7576 ImGui::Begin(name: "Example: Log", p_open);
7577 IMGUI_DEMO_MARKER("Examples/Log");
7578 if (ImGui::SmallButton(label: "[Debug] Add 5 entries"))
7579 {
7580 static int counter = 0;
7581 const char* categories[3] = { "info", "warn", "error" };
7582 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
7583 for (int n = 0; n < 5; n++)
7584 {
7585 const char* category = categories[counter % IM_ARRAYSIZE(categories)];
7586 const char* word = words[counter % IM_ARRAYSIZE(words)];
7587 log.AddLog(fmt: "[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
7588 ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
7589 counter++;
7590 }
7591 }
7592 ImGui::End();
7593
7594 // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
7595 log.Draw(title: "Example: Log", p_open);
7596}
7597
7598//-----------------------------------------------------------------------------
7599// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
7600//-----------------------------------------------------------------------------
7601
7602// Demonstrate create a window with multiple child windows.
7603static void ShowExampleAppLayout(bool* p_open)
7604{
7605 ImGui::SetNextWindowSize(size: ImVec2(500, 440), cond: ImGuiCond_FirstUseEver);
7606 if (ImGui::Begin(name: "Example: Simple layout", p_open, flags: ImGuiWindowFlags_MenuBar))
7607 {
7608 IMGUI_DEMO_MARKER("Examples/Simple layout");
7609 if (ImGui::BeginMenuBar())
7610 {
7611 if (ImGui::BeginMenu(label: "File"))
7612 {
7613 if (ImGui::MenuItem(label: "Close", shortcut: "Ctrl+W")) { *p_open = false; }
7614 ImGui::EndMenu();
7615 }
7616 ImGui::EndMenuBar();
7617 }
7618
7619 // Left
7620 static int selected = 0;
7621 {
7622 ImGui::BeginChild(str_id: "left pane", size: ImVec2(150, 0), child_flags: ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX);
7623 for (int i = 0; i < 100; i++)
7624 {
7625 // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
7626 char label[128];
7627 sprintf(s: label, format: "MyObject %d", i);
7628 if (ImGui::Selectable(label, selected: selected == i))
7629 selected = i;
7630 }
7631 ImGui::EndChild();
7632 }
7633 ImGui::SameLine();
7634
7635 // Right
7636 {
7637 ImGui::BeginGroup();
7638 ImGui::BeginChild(str_id: "item view", size: ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
7639 ImGui::Text(fmt: "MyObject: %d", selected);
7640 ImGui::Separator();
7641 if (ImGui::BeginTabBar(str_id: "##Tabs", flags: ImGuiTabBarFlags_None))
7642 {
7643 if (ImGui::BeginTabItem(label: "Description"))
7644 {
7645 ImGui::TextWrapped(fmt: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
7646 ImGui::EndTabItem();
7647 }
7648 if (ImGui::BeginTabItem(label: "Details"))
7649 {
7650 ImGui::Text(fmt: "ID: 0123456789");
7651 ImGui::EndTabItem();
7652 }
7653 ImGui::EndTabBar();
7654 }
7655 ImGui::EndChild();
7656 if (ImGui::Button(label: "Revert")) {}
7657 ImGui::SameLine();
7658 if (ImGui::Button(label: "Save")) {}
7659 ImGui::EndGroup();
7660 }
7661 }
7662 ImGui::End();
7663}
7664
7665//-----------------------------------------------------------------------------
7666// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
7667//-----------------------------------------------------------------------------
7668
7669static void ShowPlaceholderObject(const char* prefix, int uid)
7670{
7671 // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
7672 ImGui::PushID(int_id: uid);
7673
7674 // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high.
7675 ImGui::TableNextRow();
7676 ImGui::TableSetColumnIndex(column_n: 0);
7677 ImGui::AlignTextToFramePadding();
7678 bool node_open = ImGui::TreeNode(str_id: "Object", fmt: "%s_%u", prefix, uid);
7679 ImGui::TableSetColumnIndex(column_n: 1);
7680 ImGui::Text(fmt: "my sailor is rich");
7681
7682 if (node_open)
7683 {
7684 static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f };
7685 for (int i = 0; i < 8; i++)
7686 {
7687 ImGui::PushID(int_id: i); // Use field index as identifier.
7688 if (i < 2)
7689 {
7690 ShowPlaceholderObject(prefix: "Child", uid: 424242);
7691 }
7692 else
7693 {
7694 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well)
7695 ImGui::TableNextRow();
7696 ImGui::TableSetColumnIndex(column_n: 0);
7697 ImGui::AlignTextToFramePadding();
7698 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet;
7699 ImGui::TreeNodeEx(str_id: "Field", flags, fmt: "Field_%d", i);
7700
7701 ImGui::TableSetColumnIndex(column_n: 1);
7702 ImGui::SetNextItemWidth(-FLT_MIN);
7703 if (i >= 5)
7704 ImGui::InputFloat(label: "##value", v: &placeholder_members[i], step: 1.0f);
7705 else
7706 ImGui::DragFloat(label: "##value", v: &placeholder_members[i], v_speed: 0.01f);
7707 ImGui::NextColumn();
7708 }
7709 ImGui::PopID();
7710 }
7711 ImGui::TreePop();
7712 }
7713 ImGui::PopID();
7714}
7715
7716// Demonstrate create a simple property editor.
7717// This demo is a bit lackluster nowadays, would be nice to improve.
7718static void ShowExampleAppPropertyEditor(bool* p_open)
7719{
7720 ImGui::SetNextWindowSize(size: ImVec2(430, 450), cond: ImGuiCond_FirstUseEver);
7721 if (!ImGui::Begin(name: "Example: Property editor", p_open))
7722 {
7723 ImGui::End();
7724 return;
7725 }
7726
7727 IMGUI_DEMO_MARKER("Examples/Property Editor");
7728 HelpMarker(
7729 desc: "This example shows how you may implement a property editor using two columns.\n"
7730 "All objects/fields data are dummies here.\n");
7731
7732 ImGui::PushStyleVar(idx: ImGuiStyleVar_FramePadding, val: ImVec2(2, 2));
7733 if (ImGui::BeginTable(str_id: "##split", column: 2, flags: ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
7734 {
7735 ImGui::TableSetupScrollFreeze(cols: 0, rows: 1);
7736 ImGui::TableSetupColumn(label: "Object");
7737 ImGui::TableSetupColumn(label: "Contents");
7738 ImGui::TableHeadersRow();
7739
7740 // Iterate placeholder objects (all the same data)
7741 for (int obj_i = 0; obj_i < 4; obj_i++)
7742 ShowPlaceholderObject(prefix: "Object", uid: obj_i);
7743
7744 ImGui::EndTable();
7745 }
7746 ImGui::PopStyleVar();
7747 ImGui::End();
7748}
7749
7750//-----------------------------------------------------------------------------
7751// [SECTION] Example App: Long Text / ShowExampleAppLongText()
7752//-----------------------------------------------------------------------------
7753
7754// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
7755static void ShowExampleAppLongText(bool* p_open)
7756{
7757 ImGui::SetNextWindowSize(size: ImVec2(520, 600), cond: ImGuiCond_FirstUseEver);
7758 if (!ImGui::Begin(name: "Example: Long text display", p_open))
7759 {
7760 ImGui::End();
7761 return;
7762 }
7763 IMGUI_DEMO_MARKER("Examples/Long text display");
7764
7765 static int test_type = 0;
7766 static ImGuiTextBuffer log;
7767 static int lines = 0;
7768 ImGui::Text(fmt: "Printing unusually long amount of text.");
7769 ImGui::Combo(label: "Test type", current_item: &test_type,
7770 items_separated_by_zeros: "Single call to TextUnformatted()\0"
7771 "Multiple calls to Text(), clipped\0"
7772 "Multiple calls to Text(), not clipped (slow)\0");
7773 ImGui::Text(fmt: "Buffer contents: %d lines, %d bytes", lines, log.size());
7774 if (ImGui::Button(label: "Clear")) { log.clear(); lines = 0; }
7775 ImGui::SameLine();
7776 if (ImGui::Button(label: "Add 1000 lines"))
7777 {
7778 for (int i = 0; i < 1000; i++)
7779 log.appendf(fmt: "%i The quick brown fox jumps over the lazy dog\n", lines + i);
7780 lines += 1000;
7781 }
7782 ImGui::BeginChild(str_id: "Log");
7783 switch (test_type)
7784 {
7785 case 0:
7786 // Single call to TextUnformatted() with a big buffer
7787 ImGui::TextUnformatted(text: log.begin(), text_end: log.end());
7788 break;
7789 case 1:
7790 {
7791 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
7792 ImGui::PushStyleVar(idx: ImGuiStyleVar_ItemSpacing, val: ImVec2(0, 0));
7793 ImGuiListClipper clipper;
7794 clipper.Begin(items_count: lines);
7795 while (clipper.Step())
7796 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7797 ImGui::Text(fmt: "%i The quick brown fox jumps over the lazy dog", i);
7798 ImGui::PopStyleVar();
7799 break;
7800 }
7801 case 2:
7802 // Multiple calls to Text(), not clipped (slow)
7803 ImGui::PushStyleVar(idx: ImGuiStyleVar_ItemSpacing, val: ImVec2(0, 0));
7804 for (int i = 0; i < lines; i++)
7805 ImGui::Text(fmt: "%i The quick brown fox jumps over the lazy dog", i);
7806 ImGui::PopStyleVar();
7807 break;
7808 }
7809 ImGui::EndChild();
7810 ImGui::End();
7811}
7812
7813//-----------------------------------------------------------------------------
7814// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
7815//-----------------------------------------------------------------------------
7816
7817// Demonstrate creating a window which gets auto-resized according to its content.
7818static void ShowExampleAppAutoResize(bool* p_open)
7819{
7820 if (!ImGui::Begin(name: "Example: Auto-resizing window", p_open, flags: ImGuiWindowFlags_AlwaysAutoResize))
7821 {
7822 ImGui::End();
7823 return;
7824 }
7825 IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
7826
7827 static int lines = 10;
7828 ImGui::TextUnformatted(
7829 text: "Window will resize every-frame to the size of its content.\n"
7830 "Note that you probably don't want to query the window size to\n"
7831 "output your content because that would create a feedback loop.");
7832 ImGui::SliderInt(label: "Number of lines", v: &lines, v_min: 1, v_max: 20);
7833 for (int i = 0; i < lines; i++)
7834 ImGui::Text(fmt: "%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
7835 ImGui::End();
7836}
7837
7838//-----------------------------------------------------------------------------
7839// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
7840//-----------------------------------------------------------------------------
7841
7842// Demonstrate creating a window with custom resize constraints.
7843// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
7844static void ShowExampleAppConstrainedResize(bool* p_open)
7845{
7846 struct CustomConstraints
7847 {
7848 // Helper functions to demonstrate programmatic constraints
7849 // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
7850 // FIXME: None of the three demos works consistently when resizing from borders.
7851 static void AspectRatio(ImGuiSizeCallbackData* data)
7852 {
7853 float aspect_ratio = *(float*)data->UserData;
7854 data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
7855 }
7856 static void Square(ImGuiSizeCallbackData* data)
7857 {
7858 data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
7859 }
7860 static void Step(ImGuiSizeCallbackData* data)
7861 {
7862 float step = *(float*)data->UserData;
7863 data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
7864 }
7865 };
7866
7867 const char* test_desc[] =
7868 {
7869 "Between 100x100 and 500x500",
7870 "At least 100x100",
7871 "Resize vertical + lock current width",
7872 "Resize horizontal + lock current height",
7873 "Width Between 400 and 500",
7874 "Height at least 400",
7875 "Custom: Aspect Ratio 16:9",
7876 "Custom: Always Square",
7877 "Custom: Fixed Steps (100)",
7878 };
7879
7880 // Options
7881 static bool auto_resize = false;
7882 static bool window_padding = true;
7883 static int type = 6; // Aspect Ratio
7884 static int display_lines = 10;
7885
7886 // Submit constraint
7887 float aspect_ratio = 16.0f / 9.0f;
7888 float fixed_step = 100.0f;
7889 if (type == 0) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(100, 100), size_max: ImVec2(500, 500)); // Between 100x100 and 500x500
7890 if (type == 1) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(100, 100), size_max: ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
7891 if (type == 2) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(-1, 0), size_max: ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width
7892 if (type == 3) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(0, -1), size_max: ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height
7893 if (type == 4) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(400, -1), size_max: ImVec2(500, -1)); // Width Between and 400 and 500
7894 if (type == 5) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(-1, 400), size_max: ImVec2(-1, FLT_MAX)); // Height at least 400
7895 if (type == 6) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(0, 0), size_max: ImVec2(FLT_MAX, FLT_MAX), custom_callback: CustomConstraints::AspectRatio, custom_callback_data: (void*)&aspect_ratio); // Aspect ratio
7896 if (type == 7) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(0, 0), size_max: ImVec2(FLT_MAX, FLT_MAX), custom_callback: CustomConstraints::Square); // Always Square
7897 if (type == 8) ImGui::SetNextWindowSizeConstraints(size_min: ImVec2(0, 0), size_max: ImVec2(FLT_MAX, FLT_MAX), custom_callback: CustomConstraints::Step, custom_callback_data: (void*)&fixed_step); // Fixed Step
7898
7899 // Submit window
7900 if (!window_padding)
7901 ImGui::PushStyleVar(idx: ImGuiStyleVar_WindowPadding, val: ImVec2(0.0f, 0.0f));
7902 const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
7903 const bool window_open = ImGui::Begin(name: "Example: Constrained Resize", p_open, flags: window_flags);
7904 if (!window_padding)
7905 ImGui::PopStyleVar();
7906 if (window_open)
7907 {
7908 IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
7909 if (ImGui::GetIO().KeyShift)
7910 {
7911 // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture.
7912 ImVec2 avail_size = ImGui::GetContentRegionAvail();
7913 ImVec2 pos = ImGui::GetCursorScreenPos();
7914 ImGui::ColorButton(desc_id: "viewport", col: ImVec4(0.5f, 0.2f, 0.5f, 1.0f), flags: ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, size: avail_size);
7915 ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
7916 ImGui::Text(fmt: "%.2f x %.2f", avail_size.x, avail_size.y);
7917 }
7918 else
7919 {
7920 ImGui::Text(fmt: "(Hold SHIFT to display a dummy viewport)");
7921 if (ImGui::IsWindowDocked())
7922 ImGui::Text(fmt: "Warning: Sizing Constraints won't work if the window is docked!");
7923 if (ImGui::Button(label: "Set 200x200")) { ImGui::SetWindowSize(size: ImVec2(200, 200)); } ImGui::SameLine();
7924 if (ImGui::Button(label: "Set 500x500")) { ImGui::SetWindowSize(size: ImVec2(500, 500)); } ImGui::SameLine();
7925 if (ImGui::Button(label: "Set 800x200")) { ImGui::SetWindowSize(size: ImVec2(800, 200)); }
7926 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
7927 ImGui::Combo(label: "Constraint", current_item: &type, items: test_desc, IM_ARRAYSIZE(test_desc));
7928 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
7929 ImGui::DragInt(label: "Lines", v: &display_lines, v_speed: 0.2f, v_min: 1, v_max: 100);
7930 ImGui::Checkbox(label: "Auto-resize", v: &auto_resize);
7931 ImGui::Checkbox(label: "Window padding", v: &window_padding);
7932 for (int i = 0; i < display_lines; i++)
7933 ImGui::Text(fmt: "%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
7934 }
7935 }
7936 ImGui::End();
7937}
7938
7939//-----------------------------------------------------------------------------
7940// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
7941//-----------------------------------------------------------------------------
7942
7943// Demonstrate creating a simple static window with no decoration
7944// + a context-menu to choose which corner of the screen to use.
7945static void ShowExampleAppSimpleOverlay(bool* p_open)
7946{
7947 static int location = 0;
7948 ImGuiIO& io = ImGui::GetIO();
7949 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
7950 if (location >= 0)
7951 {
7952 const float PAD = 10.0f;
7953 const ImGuiViewport* viewport = ImGui::GetMainViewport();
7954 ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
7955 ImVec2 work_size = viewport->WorkSize;
7956 ImVec2 window_pos, window_pos_pivot;
7957 window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
7958 window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
7959 window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
7960 window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
7961 ImGui::SetNextWindowPos(pos: window_pos, cond: ImGuiCond_Always, pivot: window_pos_pivot);
7962 ImGui::SetNextWindowViewport(viewport->ID);
7963 window_flags |= ImGuiWindowFlags_NoMove;
7964 }
7965 else if (location == -2)
7966 {
7967 // Center window
7968 ImGui::SetNextWindowPos(pos: ImGui::GetMainViewport()->GetCenter(), cond: ImGuiCond_Always, pivot: ImVec2(0.5f, 0.5f));
7969 window_flags |= ImGuiWindowFlags_NoMove;
7970 }
7971 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
7972 if (ImGui::Begin(name: "Example: Simple overlay", p_open, flags: window_flags))
7973 {
7974 IMGUI_DEMO_MARKER("Examples/Simple Overlay");
7975 ImGui::Text(fmt: "Simple overlay\n" "(right-click to change position)");
7976 ImGui::Separator();
7977 if (ImGui::IsMousePosValid())
7978 ImGui::Text(fmt: "Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
7979 else
7980 ImGui::Text(fmt: "Mouse Position: <invalid>");
7981 if (ImGui::BeginPopupContextWindow())
7982 {
7983 if (ImGui::MenuItem(label: "Custom", NULL, selected: location == -1)) location = -1;
7984 if (ImGui::MenuItem(label: "Center", NULL, selected: location == -2)) location = -2;
7985 if (ImGui::MenuItem(label: "Top-left", NULL, selected: location == 0)) location = 0;
7986 if (ImGui::MenuItem(label: "Top-right", NULL, selected: location == 1)) location = 1;
7987 if (ImGui::MenuItem(label: "Bottom-left", NULL, selected: location == 2)) location = 2;
7988 if (ImGui::MenuItem(label: "Bottom-right", NULL, selected: location == 3)) location = 3;
7989 if (p_open && ImGui::MenuItem(label: "Close")) *p_open = false;
7990 ImGui::EndPopup();
7991 }
7992 }
7993 ImGui::End();
7994}
7995
7996//-----------------------------------------------------------------------------
7997// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
7998//-----------------------------------------------------------------------------
7999
8000// Demonstrate creating a window covering the entire screen/viewport
8001static void ShowExampleAppFullscreen(bool* p_open)
8002{
8003 static bool use_work_area = true;
8004 static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
8005
8006 // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
8007 // Based on your use case you may want one or the other.
8008 const ImGuiViewport* viewport = ImGui::GetMainViewport();
8009 ImGui::SetNextWindowPos(pos: use_work_area ? viewport->WorkPos : viewport->Pos);
8010 ImGui::SetNextWindowSize(size: use_work_area ? viewport->WorkSize : viewport->Size);
8011
8012 if (ImGui::Begin(name: "Example: Fullscreen window", p_open, flags))
8013 {
8014 ImGui::Checkbox(label: "Use work area instead of main area", v: &use_work_area);
8015 ImGui::SameLine();
8016 HelpMarker(desc: "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.");
8017
8018 ImGui::CheckboxFlags(label: "ImGuiWindowFlags_NoBackground", flags: &flags, flags_value: ImGuiWindowFlags_NoBackground);
8019 ImGui::CheckboxFlags(label: "ImGuiWindowFlags_NoDecoration", flags: &flags, flags_value: ImGuiWindowFlags_NoDecoration);
8020 ImGui::Indent();
8021 ImGui::CheckboxFlags(label: "ImGuiWindowFlags_NoTitleBar", flags: &flags, flags_value: ImGuiWindowFlags_NoTitleBar);
8022 ImGui::CheckboxFlags(label: "ImGuiWindowFlags_NoCollapse", flags: &flags, flags_value: ImGuiWindowFlags_NoCollapse);
8023 ImGui::CheckboxFlags(label: "ImGuiWindowFlags_NoScrollbar", flags: &flags, flags_value: ImGuiWindowFlags_NoScrollbar);
8024 ImGui::Unindent();
8025
8026 if (p_open && ImGui::Button(label: "Close this window"))
8027 *p_open = false;
8028 }
8029 ImGui::End();
8030}
8031
8032//-----------------------------------------------------------------------------
8033// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
8034//-----------------------------------------------------------------------------
8035
8036// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
8037// This applies to all regular items as well.
8038// Read FAQ section "How can I have multiple widgets with the same label?" for details.
8039static void ShowExampleAppWindowTitles(bool*)
8040{
8041 const ImGuiViewport* viewport = ImGui::GetMainViewport();
8042 const ImVec2 base_pos = viewport->Pos;
8043
8044 // By default, Windows are uniquely identified by their title.
8045 // You can use the "##" and "###" markers to manipulate the display/ID.
8046
8047 // Using "##" to display same title but have unique identifier.
8048 ImGui::SetNextWindowPos(pos: ImVec2(base_pos.x + 100, base_pos.y + 100), cond: ImGuiCond_FirstUseEver);
8049 ImGui::Begin(name: "Same title as another window##1");
8050 IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
8051 ImGui::Text(fmt: "This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
8052 ImGui::End();
8053
8054 ImGui::SetNextWindowPos(pos: ImVec2(base_pos.x + 100, base_pos.y + 200), cond: ImGuiCond_FirstUseEver);
8055 ImGui::Begin(name: "Same title as another window##2");
8056 ImGui::Text(fmt: "This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
8057 ImGui::End();
8058
8059 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
8060 char buf[128];
8061 sprintf(s: buf, format: "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
8062 ImGui::SetNextWindowPos(pos: ImVec2(base_pos.x + 100, base_pos.y + 300), cond: ImGuiCond_FirstUseEver);
8063 ImGui::Begin(name: buf);
8064 ImGui::Text(fmt: "This window has a changing title.");
8065 ImGui::End();
8066}
8067
8068//-----------------------------------------------------------------------------
8069// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
8070//-----------------------------------------------------------------------------
8071
8072// Add a |_| looking shape
8073static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
8074{
8075 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 } };
8076 for (const ImVec2& p : pos_norms)
8077 draw_list->PathLineTo(pos: ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
8078}
8079
8080// Demonstrate using the low-level ImDrawList to draw custom shapes.
8081static void ShowExampleAppCustomRendering(bool* p_open)
8082{
8083 if (!ImGui::Begin(name: "Example: Custom rendering", p_open))
8084 {
8085 ImGui::End();
8086 return;
8087 }
8088 IMGUI_DEMO_MARKER("Examples/Custom Rendering");
8089
8090 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
8091 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
8092 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
8093 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
8094
8095 if (ImGui::BeginTabBar(str_id: "##TabBar"))
8096 {
8097 if (ImGui::BeginTabItem(label: "Primitives"))
8098 {
8099 ImGui::PushItemWidth(item_width: -ImGui::GetFontSize() * 15);
8100 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8101
8102 // Draw gradients
8103 // (note that those are currently exacerbating our sRGB/Linear issues)
8104 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
8105 ImGui::Text(fmt: "Gradients");
8106 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
8107 {
8108 ImVec2 p0 = ImGui::GetCursorScreenPos();
8109 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
8110 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
8111 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
8112 draw_list->AddRectFilledMultiColor(p_min: p0, p_max: p1, col_upr_left: col_a, col_upr_right: col_b, col_bot_right: col_b, col_bot_left: col_a);
8113 ImGui::InvisibleButton(str_id: "##gradient1", size: gradient_size);
8114 }
8115 {
8116 ImVec2 p0 = ImGui::GetCursorScreenPos();
8117 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
8118 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
8119 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
8120 draw_list->AddRectFilledMultiColor(p_min: p0, p_max: p1, col_upr_left: col_a, col_upr_right: col_b, col_bot_right: col_b, col_bot_left: col_a);
8121 ImGui::InvisibleButton(str_id: "##gradient2", size: gradient_size);
8122 }
8123
8124 // Draw a bunch of primitives
8125 ImGui::Text(fmt: "All primitives");
8126 static float sz = 36.0f;
8127 static float thickness = 3.0f;
8128 static int ngon_sides = 6;
8129 static bool circle_segments_override = false;
8130 static int circle_segments_override_v = 12;
8131 static bool curve_segments_override = false;
8132 static int curve_segments_override_v = 8;
8133 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
8134 ImGui::DragFloat(label: "Size", v: &sz, v_speed: 0.2f, v_min: 2.0f, v_max: 100.0f, format: "%.0f");
8135 ImGui::DragFloat(label: "Thickness", v: &thickness, v_speed: 0.05f, v_min: 1.0f, v_max: 8.0f, format: "%.02f");
8136 ImGui::SliderInt(label: "N-gon sides", v: &ngon_sides, v_min: 3, v_max: 12);
8137 ImGui::Checkbox(label: "##circlesegmentoverride", v: &circle_segments_override);
8138 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: ImGui::GetStyle().ItemInnerSpacing.x);
8139 circle_segments_override |= ImGui::SliderInt(label: "Circle segments override", v: &circle_segments_override_v, v_min: 3, v_max: 40);
8140 ImGui::Checkbox(label: "##curvessegmentoverride", v: &curve_segments_override);
8141 ImGui::SameLine(offset_from_start_x: 0.0f, spacing: ImGui::GetStyle().ItemInnerSpacing.x);
8142 curve_segments_override |= ImGui::SliderInt(label: "Curves segments override", v: &curve_segments_override_v, v_min: 3, v_max: 40);
8143 ImGui::ColorEdit4(label: "Color", col: &colf.x);
8144
8145 const ImVec2 p = ImGui::GetCursorScreenPos();
8146 const ImU32 col = ImColor(colf);
8147 const float spacing = 10.0f;
8148 const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
8149 const float rounding = sz / 5.0f;
8150 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
8151 const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
8152 const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
8153 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) };
8154
8155 float x = p.x + 4.0f;
8156 float y = p.y + 4.0f;
8157 for (int n = 0; n < 2; n++)
8158 {
8159 // First line uses a thickness of 1.0f, second line uses the configurable thickness
8160 float th = (n == 0) ? 1.0f : thickness;
8161 draw_list->AddNgon(center: ImVec2(x + sz*0.5f, y + sz*0.5f), radius: sz*0.5f, col, num_segments: ngon_sides, thickness: th); x += sz + spacing; // N-gon
8162 draw_list->AddCircle(center: ImVec2(x + sz*0.5f, y + sz*0.5f), radius: sz*0.5f, col, num_segments: circle_segments, thickness: th); x += sz + spacing; // Circle
8163 draw_list->AddEllipse(center: ImVec2(x + sz*0.5f, y + sz*0.5f), radius: ImVec2(sz*0.5f, sz*0.3f), col, rot: -0.3f, num_segments: circle_segments, thickness: th); x += sz + spacing; // Ellipse
8164 draw_list->AddRect(p_min: ImVec2(x, y), p_max: ImVec2(x + sz, y + sz), col, rounding: 0.0f, flags: ImDrawFlags_None, thickness: th); x += sz + spacing; // Square
8165 draw_list->AddRect(p_min: ImVec2(x, y), p_max: ImVec2(x + sz, y + sz), col, rounding, flags: ImDrawFlags_None, thickness: th); x += sz + spacing; // Square with all rounded corners
8166 draw_list->AddRect(p_min: ImVec2(x, y), p_max: ImVec2(x + sz, y + sz), col, rounding, flags: corners_tl_br, thickness: th); x += sz + spacing; // Square with two rounded corners
8167 draw_list->AddTriangle(p1: ImVec2(x+sz*0.5f,y), p2: ImVec2(x+sz, y+sz-0.5f), p3: ImVec2(x, y+sz-0.5f), col, thickness: th);x += sz + spacing; // Triangle
8168 //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
8169 PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, flags: ImDrawFlags_Closed, thickness: th); x += sz + spacing; // Concave Shape
8170 //draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th);
8171 draw_list->AddLine(p1: ImVec2(x, y), p2: ImVec2(x + sz, y), col, thickness: th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
8172 draw_list->AddLine(p1: ImVec2(x, y), p2: ImVec2(x, y + sz), col, thickness: th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
8173 draw_list->AddLine(p1: ImVec2(x, y), p2: ImVec2(x + sz, y + sz), col, thickness: th); x += sz + spacing; // Diagonal line
8174
8175 // Path
8176 draw_list->PathArcTo(center: ImVec2(x + sz*0.5f, y + sz*0.5f), radius: sz*0.5f, a_min: 3.141592f, a_max: 3.141592f * -0.5f);
8177 draw_list->PathStroke(col, flags: ImDrawFlags_None, thickness: th);
8178 x += sz + spacing;
8179
8180 // Quadratic Bezier Curve (3 control points)
8181 draw_list->AddBezierQuadratic(p1: ImVec2(x + cp3[0].x, y + cp3[0].y), p2: ImVec2(x + cp3[1].x, y + cp3[1].y), p3: ImVec2(x + cp3[2].x, y + cp3[2].y), col, thickness: th, num_segments: curve_segments);
8182 x += sz + spacing;
8183
8184 // Cubic Bezier Curve (4 control points)
8185 draw_list->AddBezierCubic(p1: ImVec2(x + cp4[0].x, y + cp4[0].y), p2: ImVec2(x + cp4[1].x, y + cp4[1].y), p3: ImVec2(x + cp4[2].x, y + cp4[2].y), p4: ImVec2(x + cp4[3].x, y + cp4[3].y), col, thickness: th, num_segments: curve_segments);
8186
8187 x = p.x + 4;
8188 y += sz + spacing;
8189 }
8190
8191 // Filled shapes
8192 draw_list->AddNgonFilled(center: ImVec2(x + sz * 0.5f, y + sz * 0.5f), radius: sz * 0.5f, col, num_segments: ngon_sides); x += sz + spacing; // N-gon
8193 draw_list->AddCircleFilled(center: ImVec2(x + sz * 0.5f, y + sz * 0.5f), radius: sz * 0.5f, col, num_segments: circle_segments); x += sz + spacing; // Circle
8194 draw_list->AddEllipseFilled(center: ImVec2(x + sz * 0.5f, y + sz * 0.5f), radius: ImVec2(sz * 0.5f, sz * 0.3f), col, rot: -0.3f, num_segments: circle_segments); x += sz + spacing;// Ellipse
8195 draw_list->AddRectFilled(p_min: ImVec2(x, y), p_max: ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
8196 draw_list->AddRectFilled(p_min: ImVec2(x, y), p_max: ImVec2(x + sz, y + sz), col, rounding: 10.0f); x += sz + spacing; // Square with all rounded corners
8197 draw_list->AddRectFilled(p_min: ImVec2(x, y), p_max: ImVec2(x + sz, y + sz), col, rounding: 10.0f, flags: corners_tl_br); x += sz + spacing; // Square with two rounded corners
8198 draw_list->AddTriangleFilled(p1: ImVec2(x+sz*0.5f,y), p2: ImVec2(x+sz, y+sz-0.5f), p3: ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle
8199 //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
8200 PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape
8201 draw_list->AddRectFilled(p_min: ImVec2(x, y), p_max: ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness)
8202 draw_list->AddRectFilled(p_min: ImVec2(x, y), p_max: ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness)
8203 draw_list->AddRectFilled(p_min: ImVec2(x, y), p_max: ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
8204
8205 // Path
8206 draw_list->PathArcTo(center: ImVec2(x + sz * 0.5f, y + sz * 0.5f), radius: sz * 0.5f, a_min: 3.141592f * -0.5f, a_max: 3.141592f);
8207 draw_list->PathFillConvex(col);
8208 x += sz + spacing;
8209
8210 // Quadratic Bezier Curve (3 control points)
8211 draw_list->PathLineTo(pos: ImVec2(x + cp3[0].x, y + cp3[0].y));
8212 draw_list->PathBezierQuadraticCurveTo(p2: ImVec2(x + cp3[1].x, y + cp3[1].y), p3: ImVec2(x + cp3[2].x, y + cp3[2].y), num_segments: curve_segments);
8213 draw_list->PathFillConvex(col);
8214 x += sz + spacing;
8215
8216 draw_list->AddRectFilledMultiColor(p_min: ImVec2(x, y), p_max: 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));
8217 x += sz + spacing;
8218
8219 ImGui::Dummy(size: ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
8220 ImGui::PopItemWidth();
8221 ImGui::EndTabItem();
8222 }
8223
8224 if (ImGui::BeginTabItem(label: "Canvas"))
8225 {
8226 static ImVector<ImVec2> points;
8227 static ImVec2 scrolling(0.0f, 0.0f);
8228 static bool opt_enable_grid = true;
8229 static bool opt_enable_context_menu = true;
8230 static bool adding_line = false;
8231
8232 ImGui::Checkbox(label: "Enable grid", v: &opt_enable_grid);
8233 ImGui::Checkbox(label: "Enable context menu", v: &opt_enable_context_menu);
8234 ImGui::Text(fmt: "Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
8235
8236 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
8237 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
8238 // To use a child window instead we could use, e.g:
8239 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
8240 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
8241 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove);
8242 // ImGui::PopStyleColor();
8243 // ImGui::PopStyleVar();
8244 // [...]
8245 // ImGui::EndChild();
8246
8247 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
8248 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
8249 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
8250 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
8251 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
8252 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
8253
8254 // Draw border and background color
8255 ImGuiIO& io = ImGui::GetIO();
8256 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8257 draw_list->AddRectFilled(p_min: canvas_p0, p_max: canvas_p1, IM_COL32(50, 50, 50, 255));
8258 draw_list->AddRect(p_min: canvas_p0, p_max: canvas_p1, IM_COL32(255, 255, 255, 255));
8259
8260 // This will catch our interactions
8261 ImGui::InvisibleButton(str_id: "canvas", size: canvas_sz, flags: ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
8262 const bool is_hovered = ImGui::IsItemHovered(); // Hovered
8263 const bool is_active = ImGui::IsItemActive(); // Held
8264 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
8265 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
8266
8267 // Add first and second point
8268 if (is_hovered && !adding_line && ImGui::IsMouseClicked(button: ImGuiMouseButton_Left))
8269 {
8270 points.push_back(v: mouse_pos_in_canvas);
8271 points.push_back(v: mouse_pos_in_canvas);
8272 adding_line = true;
8273 }
8274 if (adding_line)
8275 {
8276 points.back() = mouse_pos_in_canvas;
8277 if (!ImGui::IsMouseDown(button: ImGuiMouseButton_Left))
8278 adding_line = false;
8279 }
8280
8281 // Pan (we use a zero mouse threshold when there's no context menu)
8282 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
8283 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
8284 if (is_active && ImGui::IsMouseDragging(button: ImGuiMouseButton_Right, lock_threshold: mouse_threshold_for_pan))
8285 {
8286 scrolling.x += io.MouseDelta.x;
8287 scrolling.y += io.MouseDelta.y;
8288 }
8289
8290 // Context menu (under default mouse threshold)
8291 ImVec2 drag_delta = ImGui::GetMouseDragDelta(button: ImGuiMouseButton_Right);
8292 if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
8293 ImGui::OpenPopupOnItemClick(str_id: "context", popup_flags: ImGuiPopupFlags_MouseButtonRight);
8294 if (ImGui::BeginPopup(str_id: "context"))
8295 {
8296 if (adding_line)
8297 points.resize(new_size: points.size() - 2);
8298 adding_line = false;
8299 if (ImGui::MenuItem(label: "Remove one", NULL, selected: false, enabled: points.Size > 0)) { points.resize(new_size: points.size() - 2); }
8300 if (ImGui::MenuItem(label: "Remove all", NULL, selected: false, enabled: points.Size > 0)) { points.clear(); }
8301 ImGui::EndPopup();
8302 }
8303
8304 // Draw grid + all lines in the canvas
8305 draw_list->PushClipRect(clip_rect_min: canvas_p0, clip_rect_max: canvas_p1, intersect_with_current_clip_rect: true);
8306 if (opt_enable_grid)
8307 {
8308 const float GRID_STEP = 64.0f;
8309 for (float x = fmodf(x: scrolling.x, y: GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
8310 draw_list->AddLine(p1: ImVec2(canvas_p0.x + x, canvas_p0.y), p2: ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
8311 for (float y = fmodf(x: scrolling.y, y: GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
8312 draw_list->AddLine(p1: ImVec2(canvas_p0.x, canvas_p0.y + y), p2: ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
8313 }
8314 for (int n = 0; n < points.Size; n += 2)
8315 draw_list->AddLine(p1: ImVec2(origin.x + points[n].x, origin.y + points[n].y), p2: ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), thickness: 2.0f);
8316 draw_list->PopClipRect();
8317
8318 ImGui::EndTabItem();
8319 }
8320
8321 if (ImGui::BeginTabItem(label: "BG/FG draw lists"))
8322 {
8323 static bool draw_bg = true;
8324 static bool draw_fg = true;
8325 ImGui::Checkbox(label: "Draw in Background draw list", v: &draw_bg);
8326 ImGui::SameLine(); HelpMarker(desc: "The Background draw list will be rendered below every Dear ImGui windows.");
8327 ImGui::Checkbox(label: "Draw in Foreground draw list", v: &draw_fg);
8328 ImGui::SameLine(); HelpMarker(desc: "The Foreground draw list will be rendered over every Dear ImGui windows.");
8329 ImVec2 window_pos = ImGui::GetWindowPos();
8330 ImVec2 window_size = ImGui::GetWindowSize();
8331 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
8332 if (draw_bg)
8333 ImGui::GetBackgroundDrawList()->AddCircle(center: window_center, radius: window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), num_segments: 0, thickness: 10 + 4);
8334 if (draw_fg)
8335 ImGui::GetForegroundDrawList()->AddCircle(center: window_center, radius: window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), num_segments: 0, thickness: 10);
8336 ImGui::EndTabItem();
8337 }
8338
8339 // Demonstrate out-of-order rendering via channels splitting
8340 // We use functions in ImDrawList as each draw list contains a convenience splitter,
8341 // but you can also instantiate your own ImDrawListSplitter if you need to nest them.
8342 if (ImGui::BeginTabItem(label: "Draw Channels"))
8343 {
8344 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8345 {
8346 ImGui::Text(fmt: "Blue shape is drawn first: appears in back");
8347 ImGui::Text(fmt: "Red shape is drawn after: appears in front");
8348 ImVec2 p0 = ImGui::GetCursorScreenPos();
8349 draw_list->AddRectFilled(p_min: ImVec2(p0.x, p0.y), p_max: ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
8350 draw_list->AddRectFilled(p_min: ImVec2(p0.x + 25, p0.y + 25), p_max: ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
8351 ImGui::Dummy(size: ImVec2(75, 75));
8352 }
8353 ImGui::Separator();
8354 {
8355 ImGui::Text(fmt: "Blue shape is drawn first, into channel 1: appears in front");
8356 ImGui::Text(fmt: "Red shape is drawn after, into channel 0: appears in back");
8357 ImVec2 p1 = ImGui::GetCursorScreenPos();
8358
8359 // Create 2 channels and draw a Blue shape THEN a Red shape.
8360 // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
8361 draw_list->ChannelsSplit(count: 2);
8362 draw_list->ChannelsSetCurrent(n: 1);
8363 draw_list->AddRectFilled(p_min: ImVec2(p1.x, p1.y), p_max: ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
8364 draw_list->ChannelsSetCurrent(n: 0);
8365 draw_list->AddRectFilled(p_min: ImVec2(p1.x + 25, p1.y + 25), p_max: ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
8366
8367 // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
8368 // This works by copying draw indices only (vertices are not copied).
8369 draw_list->ChannelsMerge();
8370 ImGui::Dummy(size: ImVec2(75, 75));
8371 ImGui::Text(fmt: "After reordering, contents of channel 0 appears below channel 1.");
8372 }
8373 ImGui::EndTabItem();
8374 }
8375
8376 ImGui::EndTabBar();
8377 }
8378
8379 ImGui::End();
8380}
8381
8382//-----------------------------------------------------------------------------
8383// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
8384//-----------------------------------------------------------------------------
8385
8386// Demonstrate using DockSpace() to create an explicit docking node within an existing window.
8387// Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking!
8388// - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
8389// - Drag from window menu button (upper-left button) to undock an entire node (all windows).
8390// - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking.
8391// About dockspaces:
8392// - Use DockSpace() to create an explicit dock node _within_ an existing window.
8393// - Use DockSpaceOverViewport() to create an explicit dock node covering the screen or a specific viewport.
8394// This is often used with ImGuiDockNodeFlags_PassthruCentralNode.
8395// - Important: Dockspaces need to be submitted _before_ any window they can host. Submit it early in your frame! (*)
8396// - Important: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
8397// e.g. if you have multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
8398// (*) because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node,
8399// because that window is submitted as part of the part of the NewFrame() call. An easy workaround is that you can create
8400// your own implicit "Debug##2" window after calling DockSpace() and leave it in the window stack for anyone to use.
8401void ShowExampleAppDockSpace(bool* p_open)
8402{
8403 // READ THIS !!!
8404 // TL;DR; this demo is more complicated than what most users you would normally use.
8405 // If we remove all options we are showcasing, this demo would become:
8406 // void ShowExampleAppDockSpace()
8407 // {
8408 // ImGui::DockSpaceOverViewport(ImGui::GetMainViewport());
8409 // }
8410 // In most cases you should be able to just call DockSpaceOverViewport() and ignore all the code below!
8411 // In this specific demo, we are not using DockSpaceOverViewport() because:
8412 // - (1) we allow the host window to be floating/moveable instead of filling the viewport (when opt_fullscreen == false)
8413 // - (2) we allow the host window to have padding (when opt_padding == true)
8414 // - (3) we expose many flags and need a way to have them visible.
8415 // - (4) we have a local menu bar in the host window (vs. you could use BeginMainMenuBar() + DockSpaceOverViewport()
8416 // in your code, but we don't here because we allow the window to be floating)
8417
8418 static bool opt_fullscreen = true;
8419 static bool opt_padding = false;
8420 static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
8421
8422 // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
8423 // because it would be confusing to have two docking targets within each others.
8424 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
8425 if (opt_fullscreen)
8426 {
8427 const ImGuiViewport* viewport = ImGui::GetMainViewport();
8428 ImGui::SetNextWindowPos(pos: viewport->WorkPos);
8429 ImGui::SetNextWindowSize(size: viewport->WorkSize);
8430 ImGui::SetNextWindowViewport(viewport->ID);
8431 ImGui::PushStyleVar(idx: ImGuiStyleVar_WindowRounding, val: 0.0f);
8432 ImGui::PushStyleVar(idx: ImGuiStyleVar_WindowBorderSize, val: 0.0f);
8433 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
8434 window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
8435 }
8436 else
8437 {
8438 dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
8439 }
8440
8441 // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
8442 // and handle the pass-thru hole, so we ask Begin() to not render a background.
8443 if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
8444 window_flags |= ImGuiWindowFlags_NoBackground;
8445
8446 // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
8447 // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
8448 // all active windows docked into it will lose their parent and become undocked.
8449 // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
8450 // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
8451 if (!opt_padding)
8452 ImGui::PushStyleVar(idx: ImGuiStyleVar_WindowPadding, val: ImVec2(0.0f, 0.0f));
8453 ImGui::Begin(name: "DockSpace Demo", p_open, flags: window_flags);
8454 if (!opt_padding)
8455 ImGui::PopStyleVar();
8456
8457 if (opt_fullscreen)
8458 ImGui::PopStyleVar(count: 2);
8459
8460 // Submit the DockSpace
8461 ImGuiIO& io = ImGui::GetIO();
8462 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
8463 {
8464 ImGuiID dockspace_id = ImGui::GetID(str_id: "MyDockSpace");
8465 ImGui::DockSpace(id: dockspace_id, size: ImVec2(0.0f, 0.0f), flags: dockspace_flags);
8466 }
8467 else
8468 {
8469 ShowDockingDisabledMessage();
8470 }
8471
8472 if (ImGui::BeginMenuBar())
8473 {
8474 if (ImGui::BeginMenu(label: "Options"))
8475 {
8476 // Disabling fullscreen would allow the window to be moved to the front of other windows,
8477 // which we can't undo at the moment without finer window depth/z control.
8478 ImGui::MenuItem(label: "Fullscreen", NULL, p_selected: &opt_fullscreen);
8479 ImGui::MenuItem(label: "Padding", NULL, p_selected: &opt_padding);
8480 ImGui::Separator();
8481
8482 if (ImGui::MenuItem(label: "Flag: NoDockingOverCentralNode", shortcut: "", selected: (dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode; }
8483 if (ImGui::MenuItem(label: "Flag: NoDockingSplit", shortcut: "", selected: (dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit; }
8484 if (ImGui::MenuItem(label: "Flag: NoUndocking", shortcut: "", selected: (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking; }
8485 if (ImGui::MenuItem(label: "Flag: NoResize", shortcut: "", selected: (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
8486 if (ImGui::MenuItem(label: "Flag: AutoHideTabBar", shortcut: "", selected: (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
8487 if (ImGui::MenuItem(label: "Flag: PassthruCentralNode", shortcut: "", selected: (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, enabled: opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
8488 ImGui::Separator();
8489
8490 if (ImGui::MenuItem(label: "Close", NULL, selected: false, enabled: p_open != NULL))
8491 *p_open = false;
8492 ImGui::EndMenu();
8493 }
8494 HelpMarker(
8495 desc: "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
8496 "- Drag from window title bar or their tab to dock/undock." "\n"
8497 "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
8498 "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
8499 "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)" "\n"
8500 "This demo app has nothing to do with enabling docking!" "\n\n"
8501 "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window." "\n\n"
8502 "Read comments in ShowExampleAppDockSpace() for more details.");
8503
8504 ImGui::EndMenuBar();
8505 }
8506
8507 ImGui::End();
8508}
8509
8510//-----------------------------------------------------------------------------
8511// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
8512//-----------------------------------------------------------------------------
8513
8514// Simplified structure to mimic a Document model
8515struct MyDocument
8516{
8517 const char* Name; // Document title
8518 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
8519 bool OpenPrev; // Copy of Open from last update.
8520 bool Dirty; // Set when the document has been modified
8521 bool WantClose; // Set when the document
8522 ImVec4 Color; // An arbitrary variable associated to the document
8523
8524 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
8525 {
8526 Name = name;
8527 Open = OpenPrev = open;
8528 Dirty = false;
8529 WantClose = false;
8530 Color = color;
8531 }
8532 void DoOpen() { Open = true; }
8533 void DoQueueClose() { WantClose = true; }
8534 void DoForceClose() { Open = false; Dirty = false; }
8535 void DoSave() { Dirty = false; }
8536
8537 // Display placeholder contents for the Document
8538 static void DisplayContents(MyDocument* doc)
8539 {
8540 ImGui::PushID(ptr_id: doc);
8541 ImGui::Text(fmt: "Document \"%s\"", doc->Name);
8542 ImGui::PushStyleColor(idx: ImGuiCol_Text, col: doc->Color);
8543 ImGui::TextWrapped(fmt: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
8544 ImGui::PopStyleColor();
8545 if (ImGui::Button(label: "Modify", size: ImVec2(100, 0)))
8546 doc->Dirty = true;
8547 ImGui::SameLine();
8548 if (ImGui::Button(label: "Save", size: ImVec2(100, 0)))
8549 doc->DoSave();
8550 ImGui::ColorEdit3(label: "color", col: &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
8551 ImGui::PopID();
8552 }
8553
8554 // Display context menu for the Document
8555 static void DisplayContextMenu(MyDocument* doc)
8556 {
8557 if (!ImGui::BeginPopupContextItem())
8558 return;
8559
8560 char buf[256];
8561 sprintf(s: buf, format: "Save %s", doc->Name);
8562 if (ImGui::MenuItem(label: buf, shortcut: "CTRL+S", selected: false, enabled: doc->Open))
8563 doc->DoSave();
8564 if (ImGui::MenuItem(label: "Close", shortcut: "CTRL+W", selected: false, enabled: doc->Open))
8565 doc->DoQueueClose();
8566 ImGui::EndPopup();
8567 }
8568};
8569
8570struct ExampleAppDocuments
8571{
8572 ImVector<MyDocument> Documents;
8573
8574 ExampleAppDocuments()
8575 {
8576 Documents.push_back(v: MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
8577 Documents.push_back(v: MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
8578 Documents.push_back(v: MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
8579 Documents.push_back(v: MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
8580 Documents.push_back(v: MyDocument("A Rather Long Title", false));
8581 Documents.push_back(v: MyDocument("Some Document", false));
8582 }
8583};
8584
8585// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
8586// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
8587// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
8588// 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
8589// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
8590// give the impression of a flicker for one frame.
8591// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
8592// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
8593static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
8594{
8595 for (MyDocument& doc : app.Documents)
8596 {
8597 if (!doc.Open && doc.OpenPrev)
8598 ImGui::SetTabItemClosed(doc.Name);
8599 doc.OpenPrev = doc.Open;
8600 }
8601}
8602
8603void ShowExampleAppDocuments(bool* p_open)
8604{
8605 static ExampleAppDocuments app;
8606
8607 // Options
8608 enum Target
8609 {
8610 Target_None,
8611 Target_Tab, // Create documents as local tab into a local tab bar
8612 Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace
8613 };
8614 static Target opt_target = Target_Tab;
8615 static bool opt_reorderable = true;
8616 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
8617
8618 // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
8619 // that we emit gets docked into the same spot as the parent window ("Example: Documents").
8620 // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
8621 // not visible, which in turn would stop submitting the "Eggplant" window.
8622 // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
8623 // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
8624
8625 bool window_contents_visible = ImGui::Begin(name: "Example: Documents", p_open, flags: ImGuiWindowFlags_MenuBar);
8626 if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
8627 {
8628 ImGui::End();
8629 return;
8630 }
8631
8632 // Menu
8633 if (ImGui::BeginMenuBar())
8634 {
8635 if (ImGui::BeginMenu(label: "File"))
8636 {
8637 int open_count = 0;
8638 for (MyDocument& doc : app.Documents)
8639 open_count += doc.Open ? 1 : 0;
8640
8641 if (ImGui::BeginMenu(label: "Open", enabled: open_count < app.Documents.Size))
8642 {
8643 for (MyDocument& doc : app.Documents)
8644 if (!doc.Open && ImGui::MenuItem(label: doc.Name))
8645 doc.DoOpen();
8646 ImGui::EndMenu();
8647 }
8648 if (ImGui::MenuItem(label: "Close All Documents", NULL, selected: false, enabled: open_count > 0))
8649 for (MyDocument& doc : app.Documents)
8650 doc.DoQueueClose();
8651 if (ImGui::MenuItem(label: "Exit", shortcut: "Ctrl+F4") && p_open)
8652 *p_open = false;
8653 ImGui::EndMenu();
8654 }
8655 ImGui::EndMenuBar();
8656 }
8657
8658 // [Debug] List documents with one checkbox for each
8659 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
8660 {
8661 MyDocument& doc = app.Documents[doc_n];
8662 if (doc_n > 0)
8663 ImGui::SameLine();
8664 ImGui::PushID(ptr_id: &doc);
8665 if (ImGui::Checkbox(label: doc.Name, v: &doc.Open))
8666 if (!doc.Open)
8667 doc.DoForceClose();
8668 ImGui::PopID();
8669 }
8670 ImGui::PushItemWidth(item_width: ImGui::GetFontSize() * 12);
8671 ImGui::Combo(label: "Output", current_item: (int*)&opt_target, items_separated_by_zeros: "None\0TabBar+Tabs\0DockSpace+Window\0");
8672 ImGui::PopItemWidth();
8673 bool redock_all = false;
8674 if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox(label: "Reorderable Tabs", v: &opt_reorderable); }
8675 if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button(label: "Redock all"); }
8676
8677 ImGui::Separator();
8678
8679 // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
8680 // They have multiple effects:
8681 // - Display a dot next to the title.
8682 // - Tab is selected when clicking the X close button.
8683 // - Closure is not assumed (will wait for user to stop submitting the tab).
8684 // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
8685 // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
8686 // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
8687 // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
8688
8689 // Tabs
8690 if (opt_target == Target_Tab)
8691 {
8692 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
8693 if (ImGui::BeginTabBar(str_id: "##tabs", flags: tab_bar_flags))
8694 {
8695 if (opt_reorderable)
8696 NotifyOfDocumentsClosedElsewhere(app);
8697
8698 // [DEBUG] Stress tests
8699 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
8700 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
8701
8702 // Submit Tabs
8703 for (MyDocument& doc : app.Documents)
8704 {
8705 if (!doc.Open)
8706 continue;
8707
8708 ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
8709 bool visible = ImGui::BeginTabItem(label: doc.Name, p_open: &doc.Open, flags: tab_flags);
8710
8711 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
8712 if (!doc.Open && doc.Dirty)
8713 {
8714 doc.Open = true;
8715 doc.DoQueueClose();
8716 }
8717
8718 MyDocument::DisplayContextMenu(doc: &doc);
8719 if (visible)
8720 {
8721 MyDocument::DisplayContents(doc: &doc);
8722 ImGui::EndTabItem();
8723 }
8724 }
8725
8726 ImGui::EndTabBar();
8727 }
8728 }
8729 else if (opt_target == Target_DockSpaceAndWindow)
8730 {
8731 if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
8732 {
8733 NotifyOfDocumentsClosedElsewhere(app);
8734
8735 // Create a DockSpace node where any window can be docked
8736 ImGuiID dockspace_id = ImGui::GetID(str_id: "MyDockSpace");
8737 ImGui::DockSpace(id: dockspace_id);
8738
8739 // Create Windows
8740 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
8741 {
8742 MyDocument* doc = &app.Documents[doc_n];
8743 if (!doc->Open)
8744 continue;
8745
8746 ImGui::SetNextWindowDockID(dock_id: dockspace_id, cond: redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
8747 ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
8748 bool visible = ImGui::Begin(name: doc->Name, p_open: &doc->Open, flags: window_flags);
8749
8750 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
8751 if (!doc->Open && doc->Dirty)
8752 {
8753 doc->Open = true;
8754 doc->DoQueueClose();
8755 }
8756
8757 MyDocument::DisplayContextMenu(doc);
8758 if (visible)
8759 MyDocument::DisplayContents(doc);
8760
8761 ImGui::End();
8762 }
8763 }
8764 else
8765 {
8766 ShowDockingDisabledMessage();
8767 }
8768 }
8769
8770 // Early out other contents
8771 if (!window_contents_visible)
8772 {
8773 ImGui::End();
8774 return;
8775 }
8776
8777 // Update closing queue
8778 static ImVector<MyDocument*> close_queue;
8779 if (close_queue.empty())
8780 {
8781 // Close queue is locked once we started a popup
8782 for (MyDocument& doc : app.Documents)
8783 if (doc.WantClose)
8784 {
8785 doc.WantClose = false;
8786 close_queue.push_back(v: &doc);
8787 }
8788 }
8789
8790 // Display closing confirmation UI
8791 if (!close_queue.empty())
8792 {
8793 int close_queue_unsaved_documents = 0;
8794 for (int n = 0; n < close_queue.Size; n++)
8795 if (close_queue[n]->Dirty)
8796 close_queue_unsaved_documents++;
8797
8798 if (close_queue_unsaved_documents == 0)
8799 {
8800 // Close documents when all are unsaved
8801 for (int n = 0; n < close_queue.Size; n++)
8802 close_queue[n]->DoForceClose();
8803 close_queue.clear();
8804 }
8805 else
8806 {
8807 if (!ImGui::IsPopupOpen(str_id: "Save?"))
8808 ImGui::OpenPopup(str_id: "Save?");
8809 if (ImGui::BeginPopupModal(name: "Save?", NULL, flags: ImGuiWindowFlags_AlwaysAutoResize))
8810 {
8811 ImGui::Text(fmt: "Save change to the following items?");
8812 float item_height = ImGui::GetTextLineHeightWithSpacing();
8813 if (ImGui::BeginChild(id: ImGui::GetID(str_id: "frame"), size: ImVec2(-FLT_MIN, 6.25f * item_height), child_flags: ImGuiChildFlags_FrameStyle))
8814 {
8815 for (int n = 0; n < close_queue.Size; n++)
8816 if (close_queue[n]->Dirty)
8817 ImGui::Text(fmt: "%s", close_queue[n]->Name);
8818 }
8819 ImGui::EndChild();
8820
8821 ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
8822 if (ImGui::Button(label: "Yes", size: button_size))
8823 {
8824 for (int n = 0; n < close_queue.Size; n++)
8825 {
8826 if (close_queue[n]->Dirty)
8827 close_queue[n]->DoSave();
8828 close_queue[n]->DoForceClose();
8829 }
8830 close_queue.clear();
8831 ImGui::CloseCurrentPopup();
8832 }
8833 ImGui::SameLine();
8834 if (ImGui::Button(label: "No", size: button_size))
8835 {
8836 for (int n = 0; n < close_queue.Size; n++)
8837 close_queue[n]->DoForceClose();
8838 close_queue.clear();
8839 ImGui::CloseCurrentPopup();
8840 }
8841 ImGui::SameLine();
8842 if (ImGui::Button(label: "Cancel", size: button_size))
8843 {
8844 close_queue.clear();
8845 ImGui::CloseCurrentPopup();
8846 }
8847 ImGui::EndPopup();
8848 }
8849 }
8850 }
8851
8852 ImGui::End();
8853}
8854
8855// End of Demo code
8856#else
8857
8858void ImGui::ShowAboutWindow(bool*) {}
8859void ImGui::ShowDemoWindow(bool*) {}
8860void ImGui::ShowUserGuide() {}
8861void ImGui::ShowStyleEditor(ImGuiStyle*) {}
8862
8863#endif
8864
8865#endif // #ifndef IMGUI_DISABLE
8866

source code of imgui/imgui_demo.cpp