openMSX
imgui_demo.cc
Go to the documentation of this file.
1// dear imgui, v1.90.5 WIP
2// (demo code)
3
4// Help:
5// - Read FAQ at http://dearimgui.com/faq
6// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
7// - Need help integrating Dear ImGui in your codebase?
8// - Read Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started
9// - Read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
10// Read top of imgui.cpp and imgui.h for many details, documentation, comments, links.
11// Get the latest version at https://github.com/ocornut/imgui
12
13//---------------------------------------------------
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 in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
58// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
59
60/*
61
62Index of this file:
63
64// [SECTION] Forward Declarations
65// [SECTION] Helpers
66// [SECTION] Demo Window / ShowDemoWindow()
67// - ShowDemoWindow()
68// - sub section: ShowDemoWindowWidgets()
69// - sub section: ShowDemoWindowLayout()
70// - sub section: ShowDemoWindowPopups()
71// - sub section: ShowDemoWindowTables()
72// - sub section: ShowDemoWindowInputs()
73// [SECTION] About Window / ShowAboutWindow()
74// [SECTION] Style Editor / ShowStyleEditor()
75// [SECTION] User Guide / ShowUserGuide()
76// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
77// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
78// [SECTION] Example App: Debug Log / ShowExampleAppLog()
79// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
80// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
81// [SECTION] Example App: Long Text / ShowExampleAppLongText()
82// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
83// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
84// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
85// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
86// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
87// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
88// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
89// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
90
91*/
92
93#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
94#define _CRT_SECURE_NO_WARNINGS
95#endif
96
97#include "imgui.h"
98#ifndef IMGUI_DISABLE
99
100// System includes
101#include <ctype.h> // toupper
102#include <limits.h> // INT_MIN, INT_MAX
103#include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
104#include <stdio.h> // vsnprintf, sscanf, printf
105#include <stdlib.h> // NULL, malloc, free, atoi
106#include <stdint.h> // intptr_t
107#if !defined(_MSC_VER) || _MSC_VER >= 1800
108#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
109#endif
110
111// Visual Studio warnings
112#ifdef _MSC_VER
113#pragma warning (disable: 4127) // condition expression is constant
114#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
115#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).
116#endif
117
118// Clang/GCC warnings with -Weverything
119#if defined(__clang__)
120#if __has_warning("-Wunknown-warning-option")
121#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!
122#endif
123#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
124#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
125#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)
126#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type
127#pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal
128#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.
129#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.
130#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
131#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.
132#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
133#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
134#elif defined(__GNUC__)
135#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
136#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
137#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure)
138#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
139#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
140#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.
141#endif
142
143// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
144#ifdef _WIN32
145#define IM_NEWLINE "\r\n"
146#else
147#define IM_NEWLINE "\n"
148#endif
149
150// Helpers
151#if defined(_MSC_VER) && !defined(snprintf)
152#define snprintf _snprintf
153#endif
154#if defined(_MSC_VER) && !defined(vsnprintf)
155#define vsnprintf _vsnprintf
156#endif
157
158// Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
159#if !defined(PRId64) && defined(_MSC_VER)
160#define PRId64 "I64d"
161#define PRIu64 "I64u"
162#elif !defined(PRId64)
163#define PRId64 "lld"
164#define PRIu64 "llu"
165#endif
166
167// Helpers macros
168// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
169// but making an exception here as those are largely simplifying code...
170// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
171#define IM_MIN(A, B) (((A) < (B)) ? (A) : (B))
172#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B))
173#define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
174
175// Enforce cdecl calling convention for functions called by the standard library,
176// in case compilation settings changed the default to e.g. __vectorcall
177#ifndef IMGUI_CDECL
178#ifdef _MSC_VER
179#define IMGUI_CDECL __cdecl
180#else
181#define IMGUI_CDECL
182#endif
183#endif
184
185//-----------------------------------------------------------------------------
186// [SECTION] Forward Declarations, Helpers
187//-----------------------------------------------------------------------------
188
189#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
190
191// Forward Declarations
192static void ShowExampleAppMainMenuBar();
193static void ShowExampleAppConsole(bool* p_open);
194static void ShowExampleAppCustomRendering(bool* p_open);
195static void ShowExampleAppDockSpace(bool* p_open);
196static void ShowExampleAppDocuments(bool* p_open);
197static void ShowExampleAppLog(bool* p_open);
198static void ShowExampleAppLayout(bool* p_open);
199static void ShowExampleAppPropertyEditor(bool* p_open);
200static void ShowExampleAppSimpleOverlay(bool* p_open);
201static void ShowExampleAppAutoResize(bool* p_open);
202static void ShowExampleAppConstrainedResize(bool* p_open);
203static void ShowExampleAppFullscreen(bool* p_open);
204static void ShowExampleAppLongText(bool* p_open);
205static void ShowExampleAppWindowTitles(bool* p_open);
206static void ShowExampleMenuFile();
207
208// We split the contents of the big ShowDemoWindow() function into smaller functions
209// (because the link time of very large functions grow non-linearly)
210static void ShowDemoWindowWidgets();
211static void ShowDemoWindowLayout();
212static void ShowDemoWindowPopups();
213static void ShowDemoWindowTables();
214static void ShowDemoWindowColumns();
215static void ShowDemoWindowInputs();
216
217//-----------------------------------------------------------------------------
218// [SECTION] Helpers
219//-----------------------------------------------------------------------------
220
221// Helper to display a little (?) mark which shows a tooltip when hovered.
222// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
223static void HelpMarker(const char* desc)
224{
225 ImGui::TextDisabled("(?)");
226 if (ImGui::BeginItemTooltip())
227 {
228 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
230 ImGui::PopTextWrapPos();
231 ImGui::EndTooltip();
232 }
233}
234
235static void ShowDockingDisabledMessage()
236{
237 ImGuiIO& io = ImGui::GetIO();
238 ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
239 ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
240 ImGui::SameLine(0.0f, 0.0f);
241 if (ImGui::SmallButton("click here"))
242 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
243}
244
245// Helper to wire demo markers located in code to an interactive browser
246typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
251#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
252
253//-----------------------------------------------------------------------------
254// [SECTION] Demo Window / ShowDemoWindow()
255//-----------------------------------------------------------------------------
256// - ShowDemoWindow()
257// - ShowDemoWindowWidgets()
258// - ShowDemoWindowLayout()
259// - ShowDemoWindowPopups()
260// - ShowDemoWindowTables()
261// - ShowDemoWindowColumns()
262// - ShowDemoWindowInputs()
263//-----------------------------------------------------------------------------
264
265// Demonstrate most Dear ImGui features (this is big function!)
266// You may execute this function to experiment with the UI and understand what it does.
267// You may then search for keywords in the code when you are interested by a specific feature.
268void ImGui::ShowDemoWindow(bool* p_open)
269{
270 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
271 // Most functions would normally just assert/crash if the context is missing.
272 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
273
274 // Examples Apps (accessible from the "Examples" menu)
275 static bool show_app_main_menu_bar = false;
276 static bool show_app_console = false;
277 static bool show_app_custom_rendering = false;
278 static bool show_app_dockspace = false;
279 static bool show_app_documents = false;
280 static bool show_app_log = false;
281 static bool show_app_layout = false;
282 static bool show_app_property_editor = false;
283 static bool show_app_simple_overlay = false;
284 static bool show_app_auto_resize = false;
285 static bool show_app_constrained_resize = false;
286 static bool show_app_fullscreen = false;
287 static bool show_app_long_text = false;
288 static bool show_app_window_titles = false;
289
290 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
291 if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
292 if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
293 if (show_app_console) ShowExampleAppConsole(&show_app_console);
294 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
295 if (show_app_log) ShowExampleAppLog(&show_app_log);
296 if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
297 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
298 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
299 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
300 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
301 if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen);
302 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
303 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
304
305 // Dear ImGui Tools (accessible from the "Tools" menu)
306 static bool show_tool_metrics = false;
307 static bool show_tool_debug_log = false;
308 static bool show_tool_id_stack_tool = false;
309 static bool show_tool_style_editor = false;
310 static bool show_tool_about = false;
311
312 if (show_tool_metrics)
313 ImGui::ShowMetricsWindow(&show_tool_metrics);
314 if (show_tool_debug_log)
315 ImGui::ShowDebugLogWindow(&show_tool_debug_log);
316 if (show_tool_id_stack_tool)
317 ImGui::ShowIDStackToolWindow(&show_tool_id_stack_tool);
318 if (show_tool_style_editor)
319 {
320 ImGui::Begin("Dear ImGui Style Editor", &show_tool_style_editor);
321 ImGui::ShowStyleEditor();
322 ImGui::End();
323 }
324 if (show_tool_about)
325 ImGui::ShowAboutWindow(&show_tool_about);
326
327 // Demonstrate the various window flags. Typically you would just use the default!
328 static bool no_titlebar = false;
329 static bool no_scrollbar = false;
330 static bool no_menu = false;
331 static bool no_move = false;
332 static bool no_resize = false;
333 static bool no_collapse = false;
334 static bool no_close = false;
335 static bool no_nav = false;
336 static bool no_background = false;
337 static bool no_bring_to_front = false;
338 static bool no_docking = false;
339 static bool unsaved_document = false;
340
341 ImGuiWindowFlags window_flags = 0;
342 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
343 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
344 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
345 if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
346 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
347 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
348 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
349 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
350 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
351 if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
352 if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
353 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
354
355 // We specify a default position/size in case there's no data in the .ini file.
356 // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
357 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
358 ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
359 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
360
361 // Main body of the Demo window starts here.
362 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
363 {
364 // Early out if the window is collapsed, as an optimization.
365 ImGui::End();
366 return;
367 }
368
369 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
370 // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
371 //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f);
372 // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
373 ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
374
375 // Menu Bar
376 if (ImGui::BeginMenuBar())
377 {
378 if (ImGui::BeginMenu("Menu"))
379 {
380 IMGUI_DEMO_MARKER("Menu/File");
381 ShowExampleMenuFile();
382 ImGui::EndMenu();
383 }
384 if (ImGui::BeginMenu("Examples"))
385 {
386 IMGUI_DEMO_MARKER("Menu/Examples");
387 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
388
389 ImGui::SeparatorText("Mini apps");
390 ImGui::MenuItem("Console", NULL, &show_app_console);
391 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
392 ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace);
393 ImGui::MenuItem("Documents", NULL, &show_app_documents);
394 ImGui::MenuItem("Log", NULL, &show_app_log);
395 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
396 ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
397 ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
398
399 ImGui::SeparatorText("Concepts");
400 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
401 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
402 ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen);
403 ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
404 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
405
406 ImGui::EndMenu();
407 }
408 //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
409 if (ImGui::BeginMenu("Tools"))
410 {
411 IMGUI_DEMO_MARKER("Menu/Tools");
412#ifndef IMGUI_DISABLE_DEBUG_TOOLS
413 const bool has_debug_tools = true;
414#else
415 const bool has_debug_tools = false;
416#endif
417 ImGui::MenuItem("Metrics/Debugger", NULL, &show_tool_metrics, has_debug_tools);
418 ImGui::MenuItem("Debug Log", NULL, &show_tool_debug_log, has_debug_tools);
419 ImGui::MenuItem("ID Stack Tool", NULL, &show_tool_id_stack_tool, has_debug_tools);
420 ImGui::MenuItem("Style Editor", NULL, &show_tool_style_editor);
421 bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent;
422 if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
423 ImGui::DebugStartItemPicker();
424 if (!is_debugger_present)
425 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.");
426 ImGui::Separator();
427 ImGui::MenuItem("About Dear ImGui", NULL, &show_tool_about);
428 ImGui::EndMenu();
429 }
430 ImGui::EndMenuBar();
431 }
432
433 ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
434 ImGui::Spacing();
435
436 IMGUI_DEMO_MARKER("Help");
437 if (ImGui::CollapsingHeader("Help"))
438 {
439 ImGui::SeparatorText("ABOUT THIS DEMO:");
440 ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
441 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
442 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
443 "and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
444
445 ImGui::SeparatorText("PROGRAMMER GUIDE:");
446 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
447 ImGui::BulletText("See comments in imgui.cpp.");
448 ImGui::BulletText("See example applications in the examples/ folder.");
449 ImGui::BulletText("Read the FAQ at https://www.dearimgui.com/faq/");
450 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
451 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
452
453 ImGui::SeparatorText("USER GUIDE:");
454 ImGui::ShowUserGuide();
455 }
456
457 IMGUI_DEMO_MARKER("Configuration");
458 if (ImGui::CollapsingHeader("Configuration"))
459 {
460 ImGuiIO& io = ImGui::GetIO();
461
462 if (ImGui::TreeNode("Configuration##2"))
463 {
464 ImGui::SeparatorText("General");
465 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
466 ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
467 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
468 ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
469 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
470 ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
471 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
472 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
473 {
474 // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
475 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
476 {
477 ImGui::SameLine();
478 ImGui::Text("<<PRESS SPACE TO DISABLE>>");
479 }
480 if (ImGui::IsKeyPressed(ImGuiKey_Space))
481 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
482 }
483 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
484 ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
485
486 ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
487 ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
488 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
489 ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
490
491 ImGui::SeparatorText("Docking");
492 ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
493 ImGui::SameLine();
494 if (io.ConfigDockingWithShift)
495 HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
496 else
497 HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
498 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
499 {
500 ImGui::Indent();
501 ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
502 ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
503 ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
504 ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)");
505 ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
506 ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
507 ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
508 ImGui::SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge.");
509 ImGui::Unindent();
510 }
511
512 ImGui::SeparatorText("Multi-viewports");
513 ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
514 ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
515 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
516 {
517 ImGui::Indent();
518 ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
519 ImGui::SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it.");
520 ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
521 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
522 ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
523 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
524 ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
525 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
526 ImGui::Unindent();
527 }
528
529 ImGui::SeparatorText("Widgets");
530 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
531 ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
532 ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive);
533 ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only).");
534 ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
535 ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
536 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
537 ImGui::SameLine(); HelpMarker("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.");
538 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
539 ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
540 ImGui::Text("Also see Style->Rendering for rendering options.");
541
542 ImGui::SeparatorText("Debug");
543 ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
544 ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.");
545 ImGui::BeginDisabled();
546 ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // .
547 ImGui::EndDisabled();
548 ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.");
549 ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
550 ImGui::SameLine(); HelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.");
551 ImGui::Checkbox("io.ConfigDebugIgnoreFocusLoss", &io.ConfigDebugIgnoreFocusLoss);
552 ImGui::SameLine(); HelpMarker("Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data.");
553 ImGui::Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings);
554 ImGui::SameLine(); HelpMarker("Option to save .ini data with extra comments (particularly helpful for Docking, but makes saving slower).");
555
556 ImGui::TreePop();
557 ImGui::Spacing();
558 }
559
560 IMGUI_DEMO_MARKER("Configuration/Backend Flags");
561 if (ImGui::TreeNode("Backend Flags"))
562 {
563 HelpMarker(
564 "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
565 "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
566
567 // Make a local copy to avoid modifying actual backend flags.
568 // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright?
569 ImGui::BeginDisabled();
570 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad);
571 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
572 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos);
573 ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports);
574 ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport);
575 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
576 ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
577 ImGui::EndDisabled();
578 ImGui::TreePop();
579 ImGui::Spacing();
580 }
581
582 IMGUI_DEMO_MARKER("Configuration/Style");
583 if (ImGui::TreeNode("Style"))
584 {
585 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
586 ImGui::ShowStyleEditor();
587 ImGui::TreePop();
588 ImGui::Spacing();
589 }
590
591 IMGUI_DEMO_MARKER("Configuration/Capture, Logging");
592 if (ImGui::TreeNode("Capture/Logging"))
593 {
594 HelpMarker(
595 "The logging API redirects all text output so you can easily capture the content of "
596 "a window or a block. Tree nodes can be automatically expanded.\n"
597 "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
598 ImGui::LogButtons();
599
600 HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
601 if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
602 {
603 ImGui::LogToClipboard();
604 ImGui::LogText("Hello, world!");
605 ImGui::LogFinish();
606 }
607 ImGui::TreePop();
608 }
609 }
610
611 IMGUI_DEMO_MARKER("Window options");
612 if (ImGui::CollapsingHeader("Window options"))
613 {
614 if (ImGui::BeginTable("split", 3))
615 {
616 ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
617 ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
618 ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
619 ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
620 ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
621 ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
622 ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
623 ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
624 ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
625 ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
626 ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
627 ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
628 ImGui::EndTable();
629 }
630 }
631
632 // All demo contents
633 ShowDemoWindowWidgets();
634 ShowDemoWindowLayout();
635 ShowDemoWindowPopups();
636 ShowDemoWindowTables();
637 ShowDemoWindowInputs();
638
639 // End of ShowDemoWindow()
640 ImGui::PopItemWidth();
641 ImGui::End();
642}
643
644static void ShowDemoWindowWidgets()
645{
646 IMGUI_DEMO_MARKER("Widgets");
647 if (!ImGui::CollapsingHeader("Widgets"))
648 return;
649
650 static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom
651 if (disable_all)
652 ImGui::BeginDisabled();
653
654 IMGUI_DEMO_MARKER("Widgets/Basic");
655 if (ImGui::TreeNode("Basic"))
656 {
657 ImGui::SeparatorText("General");
658
659 IMGUI_DEMO_MARKER("Widgets/Basic/Button");
660 static int clicked = 0;
661 if (ImGui::Button("Button"))
662 clicked++;
663 if (clicked & 1)
664 {
665 ImGui::SameLine();
666 ImGui::Text("Thanks for clicking me!");
667 }
668
669 IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox");
670 static bool check = true;
671 ImGui::Checkbox("checkbox", &check);
672
673 IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton");
674 static int e = 0;
675 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
676 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
677 ImGui::RadioButton("radio c", &e, 2);
678
679 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
680 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)");
681 for (int i = 0; i < 7; i++)
682 {
683 if (i > 0)
684 ImGui::SameLine();
685 ImGui::PushID(i);
686 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
687 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
688 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
689 ImGui::Button("Click");
690 ImGui::PopStyleColor(3);
691 ImGui::PopID();
692 }
693
694 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
695 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
696 // See 'Demo->Layout->Text Baseline Alignment' for details.
697 ImGui::AlignTextToFramePadding();
698 ImGui::Text("Hold to repeat:");
699 ImGui::SameLine();
700
701 // Arrow buttons with Repeater
702 IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
703 static int counter = 0;
704 float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
705 ImGui::PushButtonRepeat(true);
706 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
707 ImGui::SameLine(0.0f, spacing);
708 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
709 ImGui::PopButtonRepeat();
710 ImGui::SameLine();
711 ImGui::Text("%d", counter);
712
713 ImGui::Button("Tooltip");
714 ImGui::SetItemTooltip("I am a tooltip");
715
716 ImGui::LabelText("label", "Value");
717
718 ImGui::SeparatorText("Inputs");
719
720 {
721 // To wire InputText() with std::string or any other custom string type,
722 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
723 IMGUI_DEMO_MARKER("Widgets/Basic/InputText");
724 static char str0[128] = "Hello, world!";
725 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
726 ImGui::SameLine(); HelpMarker(
727 "USER:\n"
728 "Hold SHIFT or use mouse to select text.\n"
729 "CTRL+Left/Right to word jump.\n"
730 "CTRL+A or Double-Click to select all.\n"
731 "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
732 "CTRL+Z,CTRL+Y undo/redo.\n"
733 "ESCAPE to revert.\n\n"
734 "PROGRAMMER:\n"
735 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
736 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
737 "in imgui_demo.cpp).");
738
739 static char str1[128] = "";
740 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
741
742 IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
743 static int i0 = 123;
744 ImGui::InputInt("input int", &i0);
745
746 static float f0 = 0.001f;
747 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
748
749 static double d0 = 999999.00000001;
750 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
751
752 static float f1 = 1.e10f;
753 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
754 ImGui::SameLine(); HelpMarker(
755 "You can input value using the scientific notation,\n"
756 " e.g. \"1e+8\" becomes \"100000000\".");
757
758 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
759 ImGui::InputFloat3("input float3", vec4a);
760 }
761
762 ImGui::SeparatorText("Drags");
763
764 {
765 IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
766 static int i1 = 50, i2 = 42;
767 ImGui::DragInt("drag int", &i1, 1);
768 ImGui::SameLine(); HelpMarker(
769 "Click and drag to edit value.\n"
770 "Hold SHIFT/ALT for faster/slower edit.\n"
771 "Double-click or CTRL+click to input value.");
772
773 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
774
775 static float f1 = 1.00f, f2 = 0.0067f;
776 ImGui::DragFloat("drag float", &f1, 0.005f);
777 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
778 }
779
780 ImGui::SeparatorText("Sliders");
781
782 {
783 IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat");
784 static int i1 = 0;
785 ImGui::SliderInt("slider int", &i1, -1, 3);
786 ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
787
788 static float f1 = 0.123f, f2 = 0.0f;
789 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
790 ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
791
792 IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle");
793 static float angle = 0.0f;
794 ImGui::SliderAngle("slider angle", &angle);
795
796 // Using the format string to display a name instead of an integer.
797 // Here we completely omit '%d' from the format string, so it'll only display a name.
798 // This technique can also be used with DragInt().
799 IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)");
800 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
801 static int elem = Element_Fire;
802 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
803 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
804 ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here.
805 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
806 }
807
808 ImGui::SeparatorText("Selectors/Pickers");
809
810 {
811 IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4");
812 static float col1[3] = { 1.0f, 0.0f, 0.2f };
813 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
814 ImGui::ColorEdit3("color 1", col1);
815 ImGui::SameLine(); HelpMarker(
816 "Click on the color square to open a color picker.\n"
817 "Click and hold to use drag and drop.\n"
818 "Right-click on the color square to show options.\n"
819 "CTRL+click on individual component to input value.\n");
820
821 ImGui::ColorEdit4("color 2", col2);
822 }
823
824 {
825 // Using the _simplified_ one-liner Combo() api here
826 // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
827 IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
828 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
829 static int item_current = 0;
830 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
831 ImGui::SameLine(); HelpMarker(
832 "Using the simplified one-liner Combo API here.\n"
833 "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
834 }
835
836 {
837 // Using the _simplified_ one-liner ListBox() api here
838 // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
839 IMGUI_DEMO_MARKER("Widgets/Basic/ListBox");
840 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
841 static int item_current = 1;
842 ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4);
843 ImGui::SameLine(); HelpMarker(
844 "Using the simplified one-liner ListBox API here.\n"
845 "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
846 }
847
848 ImGui::TreePop();
849 }
850
851 IMGUI_DEMO_MARKER("Widgets/Tooltips");
852 if (ImGui::TreeNode("Tooltips"))
853 {
854 // Tooltips are windows following the mouse. They do not take focus away.
855 ImGui::SeparatorText("General");
856
857 // Typical use cases:
858 // - Short-form (text only): SetItemTooltip("Hello");
859 // - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); }
860
861 // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); }
862 // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); }
863
864 HelpMarker(
865 "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n"
866 "We provide a helper SetItemTooltip() function to perform the two with standards flags.");
867
868 ImVec2 sz = ImVec2(-FLT_MIN, 0.0f);
869
870 ImGui::Button("Basic", sz);
871 ImGui::SetItemTooltip("I am a tooltip");
872
873 ImGui::Button("Fancy", sz);
874 if (ImGui::BeginItemTooltip())
875 {
876 ImGui::Text("I am a fancy tooltip");
877 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
878 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
879 ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
880 ImGui::EndTooltip();
881 }
882
883 ImGui::SeparatorText("Always On");
884
885 // Showcase NOT relying on a IsItemHovered() to emit a tooltip.
886 // Here the tooltip is always emitted when 'always_on == true'.
887 static int always_on = 0;
888 ImGui::RadioButton("Off", &always_on, 0);
889 ImGui::SameLine();
890 ImGui::RadioButton("Always On (Simple)", &always_on, 1);
891 ImGui::SameLine();
892 ImGui::RadioButton("Always On (Advanced)", &always_on, 2);
893 if (always_on == 1)
894 ImGui::SetTooltip("I am following you around.");
895 else if (always_on == 2 && ImGui::BeginTooltip())
896 {
897 ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f));
898 ImGui::EndTooltip();
899 }
900
901 ImGui::SeparatorText("Custom");
902
903 HelpMarker(
904 "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize"
905 "tooltip activation details across your application. You may however decide to use custom"
906 "flags for a specific tooltip instance.");
907
908 // The following examples are passed for documentation purpose but may not be useful to most users.
909 // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from
910 // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or gamepad/keyboard is being used.
911 // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary.
912 ImGui::Button("Manual", sz);
913 if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
914 ImGui::SetTooltip("I am a manually emitted tooltip.");
915
916 ImGui::Button("DelayNone", sz);
917 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone))
918 ImGui::SetTooltip("I am a tooltip with no delay.");
919
920 ImGui::Button("DelayShort", sz);
921 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay))
922 ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort);
923
924 ImGui::Button("DelayLong", sz);
925 if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay))
926 ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal);
927
928 ImGui::Button("Stationary", sz);
929 if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary))
930 ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating.");
931
932 // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
933 // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
934 // As a result, Set
935 ImGui::BeginDisabled();
936 ImGui::Button("Disabled item", sz);
937 ImGui::EndDisabled();
938 if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
939 ImGui::SetTooltip("I am a a tooltip for a disabled item.");
940
941 ImGui::TreePop();
942 }
943
944 // Testing ImGuiOnceUponAFrame helper.
945 //static ImGuiOnceUponAFrame once;
946 //for (int i = 0; i < 5; i++)
947 // if (once)
948 // ImGui::Text("This will be displayed only once.");
949
950 IMGUI_DEMO_MARKER("Widgets/Tree Nodes");
951 if (ImGui::TreeNode("Tree Nodes"))
952 {
953 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees");
954 if (ImGui::TreeNode("Basic trees"))
955 {
956 for (int i = 0; i < 5; i++)
957 {
958 // Use SetNextItemOpen() so set the default state of a node to be open. We could
959 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
960 if (i == 0)
961 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
962
963 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
964 {
965 ImGui::Text("blah blah");
966 ImGui::SameLine();
967 if (ImGui::SmallButton("button")) {}
968 ImGui::TreePop();
969 }
970 }
971 ImGui::TreePop();
972 }
973
974 IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
975 if (ImGui::TreeNode("Advanced, with Selectable nodes"))
976 {
977 HelpMarker(
978 "This is a more typical looking tree with selectable nodes.\n"
979 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
980 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
981 static bool align_label_with_current_x_position = false;
982 static bool test_drag_and_drop = false;
983 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
984 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
985 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
986 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
987 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
988 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
989 ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
990 ImGui::Text("Hello!");
991 if (align_label_with_current_x_position)
992 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
993
994 // 'selection_mask' is dumb representation of what may be user-side selection state.
995 // You may retain selection state inside or outside your objects in whatever format you see fit.
996 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
998 static int selection_mask = (1 << 2);
999 int node_clicked = -1;
1000 for (int i = 0; i < 6; i++)
1001 {
1002 // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
1003 // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection.
1004 ImGuiTreeNodeFlags node_flags = base_flags;
1005 const bool is_selected = (selection_mask & (1 << i)) != 0;
1006 if (is_selected)
1007 node_flags |= ImGuiTreeNodeFlags_Selected;
1008 if (i < 3)
1009 {
1010 // Items 0..2 are Tree Node
1011 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
1012 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1013 node_clicked = i;
1014 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1015 {
1016 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1017 ImGui::Text("This is a drag and drop source");
1018 ImGui::EndDragDropSource();
1019 }
1020 if (node_open)
1021 {
1022 ImGui::BulletText("Blah blah\nBlah Blah");
1023 ImGui::TreePop();
1024 }
1025 }
1026 else
1027 {
1028 // Items 3..5 are Tree Leaves
1029 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
1030 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
1031 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
1032 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
1033 if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen())
1034 node_clicked = i;
1035 if (test_drag_and_drop && ImGui::BeginDragDropSource())
1036 {
1037 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
1038 ImGui::Text("This is a drag and drop source");
1039 ImGui::EndDragDropSource();
1040 }
1041 }
1042 }
1043 if (node_clicked != -1)
1044 {
1045 // Update selection state
1046 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
1047 if (ImGui::GetIO().KeyCtrl)
1048 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
1049 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
1050 selection_mask = (1 << node_clicked); // Click to single-select
1051 }
1052 if (align_label_with_current_x_position)
1053 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
1054 ImGui::TreePop();
1055 }
1056 ImGui::TreePop();
1057 }
1058
1059 IMGUI_DEMO_MARKER("Widgets/Collapsing Headers");
1060 if (ImGui::TreeNode("Collapsing Headers"))
1061 {
1062 static bool closable_group = true;
1063 ImGui::Checkbox("Show 2nd header", &closable_group);
1064 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
1065 {
1066 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1067 for (int i = 0; i < 5; i++)
1068 ImGui::Text("Some content %d", i);
1069 }
1070 if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
1071 {
1072 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1073 for (int i = 0; i < 5; i++)
1074 ImGui::Text("More content %d", i);
1075 }
1076 /*
1077 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
1078 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
1079 */
1080 ImGui::TreePop();
1081 }
1082
1083 IMGUI_DEMO_MARKER("Widgets/Bullets");
1084 if (ImGui::TreeNode("Bullets"))
1085 {
1086 ImGui::BulletText("Bullet point 1");
1087 ImGui::BulletText("Bullet point 2\nOn multiple lines");
1088 if (ImGui::TreeNode("Tree node"))
1089 {
1090 ImGui::BulletText("Another bullet point");
1091 ImGui::TreePop();
1092 }
1093 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
1094 ImGui::Bullet(); ImGui::SmallButton("Button");
1095 ImGui::TreePop();
1096 }
1097
1098 IMGUI_DEMO_MARKER("Widgets/Text");
1099 if (ImGui::TreeNode("Text"))
1100 {
1101 IMGUI_DEMO_MARKER("Widgets/Text/Colored Text");
1102 if (ImGui::TreeNode("Colorful Text"))
1103 {
1104 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
1105 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
1106 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
1107 ImGui::TextDisabled("Disabled");
1108 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
1109 ImGui::TreePop();
1110 }
1111
1112 IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping");
1113 if (ImGui::TreeNode("Word Wrapping"))
1114 {
1115 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
1116 ImGui::TextWrapped(
1117 "This text should automatically wrap on the edge of the window. The current implementation "
1118 "for text wrapping follows simple rules suitable for English and possibly other languages.");
1119 ImGui::Spacing();
1120
1121 static float wrap_width = 200.0f;
1122 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
1123
1124 ImDrawList* draw_list = ImGui::GetWindowDrawList();
1125 for (int n = 0; n < 2; n++)
1126 {
1127 ImGui::Text("Test paragraph %d:", n);
1128 ImVec2 pos = ImGui::GetCursorScreenPos();
1129 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
1130 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
1131 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
1132 if (n == 0)
1133 ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width);
1134 else
1135 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
1136
1137 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
1138 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
1139 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
1140 ImGui::PopTextWrapPos();
1141 }
1142
1143 ImGui::TreePop();
1144 }
1145
1146 IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text");
1147 if (ImGui::TreeNode("UTF-8 Text"))
1148 {
1149 // UTF-8 test with Japanese characters
1150 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
1151 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
1152 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
1153 // can save your source files as 'UTF-8 without signature').
1154 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
1155 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
1156 // Don't do this in your application! Please use u8"text in any language" in your application!
1157 // Note that characters values are preserved even by InputText() if the font cannot be displayed,
1158 // so you can safely copy & paste garbled characters into another application.
1159 ImGui::TextWrapped(
1160 "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. "
1161 "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
1162 "Read docs/FONTS.md for details.");
1163 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
1164 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
1165 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
1166 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
1167 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
1168 ImGui::TreePop();
1169 }
1170 ImGui::TreePop();
1171 }
1172
1173 IMGUI_DEMO_MARKER("Widgets/Images");
1174 if (ImGui::TreeNode("Images"))
1175 {
1176 ImGuiIO& io = ImGui::GetIO();
1177 ImGui::TextWrapped(
1178 "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
1179 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1180 "Hover the texture for a zoomed view!");
1181
1182 // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1183 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
1184 // will be passed to the rendering backend via the ImDrawCmd structure.
1185 // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1186 // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
1187 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
1188 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1189 // More:
1190 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1191 // to ImGui::Image(), and gather width/height through your own functions, etc.
1192 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1193 // it will help you debug issues if you are confused about it.
1194 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1195 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1196 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1197 ImTextureID my_tex_id = io.Fonts->TexID;
1198 float my_tex_w = (float)io.Fonts->TexWidth;
1199 float my_tex_h = (float)io.Fonts->TexHeight;
1200 {
1201 static bool use_text_color_for_tint = false;
1202 ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
1203 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1204 ImVec2 pos = ImGui::GetCursorScreenPos();
1205 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1206 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1207 ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1208 ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
1209 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
1210 if (ImGui::BeginItemTooltip())
1211 {
1212 float region_sz = 32.0f;
1213 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1214 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1215 float zoom = 4.0f;
1216 if (region_x < 0.0f) { region_x = 0.0f; }
1217 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1218 if (region_y < 0.0f) { region_y = 0.0f; }
1219 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1220 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
1221 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1222 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1223 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1224 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
1225 ImGui::EndTooltip();
1226 }
1227 }
1228
1229 IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons");
1230 ImGui::TextWrapped("And now some textured buttons..");
1231 static int pressed_count = 0;
1232 for (int i = 0; i < 8; i++)
1233 {
1234 // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures.
1235 // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation.
1236 // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1237 ImGui::PushID(i);
1238 if (i > 0)
1239 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f));
1240 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
1241 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
1242 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture
1243 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
1244 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1245 if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col))
1246 pressed_count += 1;
1247 if (i > 0)
1248 ImGui::PopStyleVar();
1249 ImGui::PopID();
1250 ImGui::SameLine();
1251 }
1252 ImGui::NewLine();
1253 ImGui::Text("Pressed %d times.", pressed_count);
1254 ImGui::TreePop();
1255 }
1256
1257 IMGUI_DEMO_MARKER("Widgets/Combo");
1258 if (ImGui::TreeNode("Combo"))
1259 {
1260 // Combo Boxes are also called "Dropdown" in other systems
1261 // Expose flags as checkbox for the demo
1262 static ImGuiComboFlags flags = 0;
1263 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1264 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1265 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1266 flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags
1267 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1268 flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags
1269 if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview))
1270 flags &= ~ImGuiComboFlags_NoPreview;
1271
1272 // Override default popup height
1273 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall))
1274 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall);
1275 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular))
1276 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular);
1277 if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest))
1278 flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest);
1279
1280 // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1281 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1282 // stored in the object itself, etc.)
1283 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1284 static int item_current_idx = 0; // Here we store our selection data as an index.
1285
1286 // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
1287 const char* combo_preview_value = items[item_current_idx];
1288
1289 if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1290 {
1291 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1292 {
1293 const bool is_selected = (item_current_idx == n);
1294 if (ImGui::Selectable(items[n], is_selected))
1295 item_current_idx = n;
1296
1297 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1298 if (is_selected)
1299 ImGui::SetItemDefaultFocus();
1300 }
1301 ImGui::EndCombo();
1302 }
1303
1304 ImGui::Spacing();
1305 ImGui::SeparatorText("One-liner variants");
1306 HelpMarker("Flags above don't apply to this section.");
1307
1308 // Simplified one-liner Combo() API, using values packed in a single constant string
1309 // This is a convenience for when the selection set is small and known at compile-time.
1310 static int item_current_2 = 0;
1311 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1312
1313 // Simplified one-liner Combo() using an array of const char*
1314 // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1315 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1316 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
1317
1318 // Simplified one-liner Combo() using an accessor function
1319 static int item_current_4 = 0;
1320 ImGui::Combo("combo 4 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items));
1321
1322 ImGui::TreePop();
1323 }
1324
1325 IMGUI_DEMO_MARKER("Widgets/List Boxes");
1326 if (ImGui::TreeNode("List boxes"))
1327 {
1328 // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild()
1329 // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
1330 // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild()
1331 // to always be called (inconsistent with BeginListBox()/EndListBox()).
1332
1333 // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1334 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1335 // stored in the object itself, etc.)
1336 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1337 static int item_current_idx = 0; // Here we store our selection data as an index.
1338 if (ImGui::BeginListBox("listbox 1"))
1339 {
1340 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1341 {
1342 const bool is_selected = (item_current_idx == n);
1343 if (ImGui::Selectable(items[n], is_selected))
1344 item_current_idx = n;
1345
1346 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1347 if (is_selected)
1348 ImGui::SetItemDefaultFocus();
1349 }
1350 ImGui::EndListBox();
1351 }
1352
1353 // Custom size: use all width, 5 items tall
1354 ImGui::Text("Full-width:");
1355 if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1356 {
1357 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1358 {
1359 const bool is_selected = (item_current_idx == n);
1360 if (ImGui::Selectable(items[n], is_selected))
1361 item_current_idx = n;
1362
1363 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1364 if (is_selected)
1365 ImGui::SetItemDefaultFocus();
1366 }
1367 ImGui::EndListBox();
1368 }
1369
1370 ImGui::TreePop();
1371 }
1372
1373 IMGUI_DEMO_MARKER("Widgets/Selectables");
1374 if (ImGui::TreeNode("Selectables"))
1375 {
1376 // Selectable() has 2 overloads:
1377 // - The one taking "bool selected" as a read-only selection information.
1378 // When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1379 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1380 // The earlier is more flexible, as in real application your selection may be stored in many different ways
1381 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1382 IMGUI_DEMO_MARKER("Widgets/Selectables/Basic");
1383 if (ImGui::TreeNode("Basic"))
1384 {
1385 static bool selection[5] = { false, true, false, false };
1386 ImGui::Selectable("1. I am selectable", &selection[0]);
1387 ImGui::Selectable("2. I am selectable", &selection[1]);
1388 ImGui::Selectable("3. I am selectable", &selection[2]);
1389 if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick))
1390 if (ImGui::IsMouseDoubleClicked(0))
1391 selection[3] = !selection[3];
1392 ImGui::TreePop();
1393 }
1394
1395 IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection");
1396 if (ImGui::TreeNode("Selection State: Single Selection"))
1397 {
1398 static int selected = -1;
1399 for (int n = 0; n < 5; n++)
1400 {
1401 char buf[32];
1402 sprintf(buf, "Object %d", n);
1403 if (ImGui::Selectable(buf, selected == n))
1404 selected = n;
1405 }
1406 ImGui::TreePop();
1407 }
1408 IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple Selection");
1409 if (ImGui::TreeNode("Selection State: Multiple Selection"))
1410 {
1411 HelpMarker("Hold CTRL and click to select multiple items.");
1412 static bool selection[5] = { false, false, false, false, false };
1413 for (int n = 0; n < 5; n++)
1414 {
1415 char buf[32];
1416 sprintf(buf, "Object %d", n);
1417 if (ImGui::Selectable(buf, selection[n]))
1418 {
1419 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
1420 memset(selection, 0, sizeof(selection));
1421 selection[n] ^= 1;
1422 }
1423 }
1424 ImGui::TreePop();
1425 }
1426 IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
1427 if (ImGui::TreeNode("Rendering more items on the same line"))
1428 {
1429 // (1) Using SetNextItemAllowOverlap()
1430 // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically.
1431 static bool selected[3] = { false, false, false };
1432 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1");
1433 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2");
1434 ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3");
1435 ImGui::TreePop();
1436 }
1437
1438 IMGUI_DEMO_MARKER("Widgets/Selectables/In columns");
1439 if (ImGui::TreeNode("In columns"))
1440 {
1441 static bool selected[10] = {};
1442
1443 if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1444 {
1445 for (int i = 0; i < 10; i++)
1446 {
1447 char label[32];
1448 sprintf(label, "Item %d", i);
1449 ImGui::TableNextColumn();
1450 ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
1451 }
1452 ImGui::EndTable();
1453 }
1454 ImGui::Spacing();
1455 if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1456 {
1457 for (int i = 0; i < 10; i++)
1458 {
1459 char label[32];
1460 sprintf(label, "Item %d", i);
1461 ImGui::TableNextRow();
1462 ImGui::TableNextColumn();
1463 ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
1464 ImGui::TableNextColumn();
1465 ImGui::Text("Some other contents");
1466 ImGui::TableNextColumn();
1467 ImGui::Text("123456");
1468 }
1469 ImGui::EndTable();
1470 }
1471 ImGui::TreePop();
1472 }
1473
1474 IMGUI_DEMO_MARKER("Widgets/Selectables/Grid");
1475 if (ImGui::TreeNode("Grid"))
1476 {
1477 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
1478
1479 // Add in a bit of silly fun...
1480 const float time = (float)ImGui::GetTime();
1481 const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
1482 if (winning_state)
1483 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
1484
1485 for (int y = 0; y < 4; y++)
1486 for (int x = 0; x < 4; x++)
1487 {
1488 if (x > 0)
1489 ImGui::SameLine();
1490 ImGui::PushID(y * 4 + x);
1491 if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
1492 {
1493 // Toggle clicked cell + toggle neighbors
1494 selected[y][x] ^= 1;
1495 if (x > 0) { selected[y][x - 1] ^= 1; }
1496 if (x < 3) { selected[y][x + 1] ^= 1; }
1497 if (y > 0) { selected[y - 1][x] ^= 1; }
1498 if (y < 3) { selected[y + 1][x] ^= 1; }
1499 }
1500 ImGui::PopID();
1501 }
1502
1503 if (winning_state)
1504 ImGui::PopStyleVar();
1505 ImGui::TreePop();
1506 }
1507 IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
1508 if (ImGui::TreeNode("Alignment"))
1509 {
1510 HelpMarker(
1511 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1512 "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1513 "left-align otherwise it becomes difficult to layout multiple items on a same line");
1514 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1515 for (int y = 0; y < 3; y++)
1516 {
1517 for (int x = 0; x < 3; x++)
1518 {
1519 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1520 char name[32];
1521 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
1522 if (x > 0) ImGui::SameLine();
1523 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
1524 ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
1525 ImGui::PopStyleVar();
1526 }
1527 }
1528 ImGui::TreePop();
1529 }
1530 ImGui::TreePop();
1531 }
1532
1533 // To wire InputText() with std::string or any other custom string type,
1534 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1535 IMGUI_DEMO_MARKER("Widgets/Text Input");
1536 if (ImGui::TreeNode("Text Input"))
1537 {
1538 IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input");
1539 if (ImGui::TreeNode("Multi-line Text Input"))
1540 {
1541 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1542 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1543 static char text[1024 * 16] =
1544 "/*\n"
1545 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1546 " the hexadecimal encoding of one offending instruction,\n"
1547 " more formally, the invalid operand with locked CMPXCHG8B\n"
1548 " instruction bug, is a design flaw in the majority of\n"
1549 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1550 " processors (all in the P5 microarchitecture).\n"
1551 "*/\n\n"
1552 "label:\n"
1553 "\tlock cmpxchg8b eax\n";
1554
1555 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1556 HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include <string> in here)");
1557 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1558 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
1559 ImGui::SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets.");
1560 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
1561 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1562 ImGui::TreePop();
1563 }
1564
1565 IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input");
1566 if (ImGui::TreeNode("Filtered Text Input"))
1567 {
1568 struct TextFilters
1569 {
1570 // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback)
1571 static int FilterCasingSwap(ImGuiInputTextCallbackData* data)
1572 {
1573 if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase
1574 else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase
1575 return 0;
1576 }
1577
1578 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out)
1579 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1580 {
1581 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
1582 return 0;
1583 return 1;
1584 }
1585 };
1586
1587 static char buf1[32] = ""; ImGui::InputText("default", buf1, 32);
1588 static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal);
1589 static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1590 static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase);
1591 static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank);
1592 static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters.
1593 static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters.
1594 ImGui::TreePop();
1595 }
1596
1597 IMGUI_DEMO_MARKER("Widgets/Text Input/Password input");
1598 if (ImGui::TreeNode("Password Input"))
1599 {
1600 static char password[64] = "password123";
1601 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1602 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1603 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1604 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
1605 ImGui::TreePop();
1606 }
1607
1608 IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks");
1609 if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
1610 {
1611 struct Funcs
1612 {
1613 static int MyCallback(ImGuiInputTextCallbackData* data)
1614 {
1615 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1616 {
1617 data->InsertChars(data->CursorPos, "..");
1618 }
1619 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1620 {
1621 if (data->EventKey == ImGuiKey_UpArrow)
1622 {
1623 data->DeleteChars(0, data->BufTextLen);
1624 data->InsertChars(0, "Pressed Up!");
1625 data->SelectAll();
1626 }
1627 else if (data->EventKey == ImGuiKey_DownArrow)
1628 {
1629 data->DeleteChars(0, data->BufTextLen);
1630 data->InsertChars(0, "Pressed Down!");
1631 data->SelectAll();
1632 }
1633 }
1634 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1635 {
1636 // Toggle casing of first character
1637 char c = data->Buf[0];
1638 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1639 data->BufDirty = true;
1640
1641 // Increment a counter
1642 int* p_int = (int*)data->UserData;
1643 *p_int = *p_int + 1;
1644 }
1645 return 0;
1646 }
1647 };
1648 static char buf1[64];
1649 ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
1650 ImGui::SameLine(); HelpMarker(
1651 "Here we append \"..\" each time Tab is pressed. "
1652 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1653
1654 static char buf2[64];
1655 ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
1656 ImGui::SameLine(); HelpMarker(
1657 "Here we replace and select text each time Up/Down are pressed. "
1658 "See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1659
1660 static char buf3[64];
1661 static int edit_count = 0;
1662 ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
1663 ImGui::SameLine(); HelpMarker(
1664 "Here we toggle the casing of the first character on every edit + count edits.");
1665 ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
1666
1667 ImGui::TreePop();
1668 }
1669
1670 IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback");
1671 if (ImGui::TreeNode("Resize Callback"))
1672 {
1673 // To wire InputText() with std::string or any other custom string type,
1674 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1675 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1676 HelpMarker(
1677 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1678 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1679 struct Funcs
1680 {
1681 static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1682 {
1683 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1684 {
1685 ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1686 IM_ASSERT(my_str->begin() == data->Buf);
1687 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1688 data->Buf = my_str->begin();
1689 }
1690 return 0;
1691 }
1692
1693 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1694 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1695 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1696 {
1697 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1698 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
1699 }
1700 };
1701
1702 // For this demo we are using ImVector as a string container.
1703 // Note that because we need to store a terminating zero character, our size/capacity are 1 more
1704 // than usually reported by a typical string class.
1705 static ImVector<char> my_str;
1706 if (my_str.empty())
1707 my_str.push_back(0);
1708 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1709 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1710 ImGui::TreePop();
1711 }
1712
1713 IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous");
1714 if (ImGui::TreeNode("Miscellaneous"))
1715 {
1716 static char buf1[16];
1717 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll;
1718 ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll);
1719 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1720 ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo);
1721 ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags);
1722 ImGui::TreePop();
1723 }
1724
1725 ImGui::TreePop();
1726 }
1727
1728 // Tabs
1729 IMGUI_DEMO_MARKER("Widgets/Tabs");
1730 if (ImGui::TreeNode("Tabs"))
1731 {
1732 IMGUI_DEMO_MARKER("Widgets/Tabs/Basic");
1733 if (ImGui::TreeNode("Basic"))
1734 {
1735 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1736 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1737 {
1738 if (ImGui::BeginTabItem("Avocado"))
1739 {
1740 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
1741 ImGui::EndTabItem();
1742 }
1743 if (ImGui::BeginTabItem("Broccoli"))
1744 {
1745 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
1746 ImGui::EndTabItem();
1747 }
1748 if (ImGui::BeginTabItem("Cucumber"))
1749 {
1750 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
1751 ImGui::EndTabItem();
1752 }
1753 ImGui::EndTabBar();
1754 }
1755 ImGui::Separator();
1756 ImGui::TreePop();
1757 }
1758
1759 IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button");
1760 if (ImGui::TreeNode("Advanced & Close Button"))
1761 {
1762 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1763 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1764 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
1765 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
1766 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1767 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1768 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1769 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1770 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1771 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1772 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1773 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1774
1775 // Tab Bar
1776 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1777 static bool opened[4] = { true, true, true, true }; // Persistent user state
1778 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1779 {
1780 if (n > 0) { ImGui::SameLine(); }
1781 ImGui::Checkbox(names[n], &opened[n]);
1782 }
1783
1784 // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
1785 // the underlying bool will be set to false when the tab is closed.
1786 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1787 {
1788 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1789 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
1790 {
1791 ImGui::Text("This is the %s tab!", names[n]);
1792 if (n & 1)
1793 ImGui::Text("I am an odd tab.");
1794 ImGui::EndTabItem();
1795 }
1796 ImGui::EndTabBar();
1797 }
1798 ImGui::Separator();
1799 ImGui::TreePop();
1800 }
1801
1802 IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags");
1803 if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
1804 {
1805 static ImVector<int> active_tabs;
1806 static int next_tab_id = 0;
1807 if (next_tab_id == 0) // Initialize with some default tabs
1808 for (int i = 0; i < 3; i++)
1809 active_tabs.push_back(next_tab_id++);
1810
1811 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
1812 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
1813 // but they tend to make more sense together)
1814 static bool show_leading_button = true;
1815 static bool show_trailing_button = true;
1816 ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
1817 ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
1818
1819 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
1820 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
1821 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1822 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1823 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1824 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1825 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1826
1827 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1828 {
1829 // Demo a Leading TabItemButton(): click the "?" button to open a menu
1830 if (show_leading_button)
1831 if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
1832 ImGui::OpenPopup("MyHelpMenu");
1833 if (ImGui::BeginPopup("MyHelpMenu"))
1834 {
1835 ImGui::Selectable("Hello!");
1836 ImGui::EndPopup();
1837 }
1838
1839 // Demo Trailing Tabs: click the "+" button to add a new tab.
1840 // (In your app you may want to use a font icon instead of the "+")
1841 // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
1842 if (show_trailing_button)
1843 if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
1844 active_tabs.push_back(next_tab_id++); // Add new tab
1845
1846 // Submit our regular tabs
1847 for (int n = 0; n < active_tabs.Size; )
1848 {
1849 bool open = true;
1850 char name[16];
1851 snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
1852 if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
1853 {
1854 ImGui::Text("This is the %s tab!", name);
1855 ImGui::EndTabItem();
1856 }
1857
1858 if (!open)
1859 active_tabs.erase(active_tabs.Data + n);
1860 else
1861 n++;
1862 }
1863
1864 ImGui::EndTabBar();
1865 }
1866 ImGui::Separator();
1867 ImGui::TreePop();
1868 }
1869 ImGui::TreePop();
1870 }
1871
1872 // Plot/Graph widgets are not very good.
1873 // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot
1874 // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions)
1875 IMGUI_DEMO_MARKER("Widgets/Plotting");
1876 if (ImGui::TreeNode("Plotting"))
1877 {
1878 static bool animate = true;
1879 ImGui::Checkbox("Animate", &animate);
1880
1881 // Plot as lines and plot as histogram
1882 IMGUI_DEMO_MARKER("Widgets/Plotting/PlotLines, PlotHistogram");
1883 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1884 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
1885 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
1886
1887 // Fill an array of contiguous float values to plot
1888 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
1889 // and the sizeof() of your structure in the "stride" parameter.
1890 static float values[90] = {};
1891 static int values_offset = 0;
1892 static double refresh_time = 0.0;
1893 if (!animate || refresh_time == 0.0)
1894 refresh_time = ImGui::GetTime();
1895 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
1896 {
1897 static float phase = 0.0f;
1898 values[values_offset] = cosf(phase);
1899 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
1900 phase += 0.10f * values_offset;
1901 refresh_time += 1.0f / 60.0f;
1902 }
1903
1904 // Plots can display overlay texts
1905 // (in this example, we will display an average value)
1906 {
1907 float average = 0.0f;
1908 for (int n = 0; n < IM_ARRAYSIZE(values); n++)
1909 average += values[n];
1910 average /= (float)IM_ARRAYSIZE(values);
1911 char overlay[32];
1912 sprintf(overlay, "avg %f", average);
1913 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
1914 }
1915
1916 // Use functions to generate output
1917 // FIXME: This is actually VERY awkward because current plot API only pass in indices.
1918 // We probably want an API passing floats and user provide sample rate/count.
1919 struct Funcs
1920 {
1921 static float Sin(void*, int i) { return sinf(i * 0.1f); }
1922 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
1923 };
1924 static int func_type = 0, display_count = 70;
1925 ImGui::SeparatorText("Functions");
1926 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
1927 ImGui::Combo("func", &func_type, "Sin\0Saw\0");
1928 ImGui::SameLine();
1929 ImGui::SliderInt("Sample count", &display_count, 1, 400);
1930 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
1931 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
1932 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
1933 ImGui::Separator();
1934
1935 // Animate a simple progress bar
1936 IMGUI_DEMO_MARKER("Widgets/Plotting/ProgressBar");
1937 static float progress = 0.0f, progress_dir = 1.0f;
1938 if (animate)
1939 {
1940 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
1941 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
1942 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
1943 }
1944
1945 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
1946 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
1947 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
1948 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
1949 ImGui::Text("Progress Bar");
1950
1951 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
1952 char buf[32];
1953 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
1954 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
1955 ImGui::TreePop();
1956 }
1957
1958 IMGUI_DEMO_MARKER("Widgets/Color");
1959 if (ImGui::TreeNode("Color/Picker Widgets"))
1960 {
1961 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
1962
1963 static bool alpha_preview = true;
1964 static bool alpha_half_preview = false;
1965 static bool drag_and_drop = true;
1966 static bool options_menu = true;
1967 static bool hdr = false;
1968 ImGui::SeparatorText("Options");
1969 ImGui::Checkbox("With Alpha Preview", &alpha_preview);
1970 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
1971 ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
1972 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
1973 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
1974 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);
1975
1976 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit");
1977 ImGui::SeparatorText("Inline color editor");
1978 ImGui::Text("Color widget:");
1979 ImGui::SameLine(); HelpMarker(
1980 "Click on the color square to open a color picker.\n"
1981 "CTRL+click on individual component to input value.\n");
1982 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
1983
1984 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)");
1985 ImGui::Text("Color widget HSV with Alpha:");
1986 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
1987
1988 IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)");
1989 ImGui::Text("Color widget with Float Display:");
1990 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
1991
1992 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)");
1993 ImGui::Text("Color button with Picker:");
1994 ImGui::SameLine(); HelpMarker(
1995 "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
1996 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
1997 "be used for the tooltip and picker popup.");
1998 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
1999
2000 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)");
2001 ImGui::Text("Color button with Custom Picker Popup:");
2002
2003 // Generate a default palette. The palette will persist and can be edited.
2004 static bool saved_palette_init = true;
2005 static ImVec4 saved_palette[32] = {};
2006 if (saved_palette_init)
2007 {
2008 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2009 {
2010 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
2011 saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
2012 saved_palette[n].w = 1.0f; // Alpha
2013 }
2014 saved_palette_init = false;
2015 }
2016
2017 static ImVec4 backup_color;
2018 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
2019 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
2020 open_popup |= ImGui::Button("Palette");
2021 if (open_popup)
2022 {
2023 ImGui::OpenPopup("mypicker");
2024 backup_color = color;
2025 }
2026 if (ImGui::BeginPopup("mypicker"))
2027 {
2028 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
2029 ImGui::Separator();
2030 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
2031 ImGui::SameLine();
2032
2033 ImGui::BeginGroup(); // Lock X position
2034 ImGui::Text("Current");
2035 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
2036 ImGui::Text("Previous");
2037 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
2038 color = backup_color;
2039 ImGui::Separator();
2040 ImGui::Text("Palette");
2041 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
2042 {
2043 ImGui::PushID(n);
2044 if ((n % 8) != 0)
2045 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
2046
2047 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
2048 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
2049 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
2050
2051 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
2052 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
2053 if (ImGui::BeginDragDropTarget())
2054 {
2055 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
2056 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
2057 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
2058 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
2059 ImGui::EndDragDropTarget();
2060 }
2061
2062 ImGui::PopID();
2063 }
2064 ImGui::EndGroup();
2065 ImGui::EndPopup();
2066 }
2067
2068 IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)");
2069 ImGui::Text("Color button only:");
2070 static bool no_border = false;
2071 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
2072 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
2073
2074 IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker");
2075 ImGui::SeparatorText("Color picker");
2076 static bool alpha = true;
2077 static bool alpha_bar = true;
2078 static bool side_preview = true;
2079 static bool ref_color = false;
2080 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
2081 static int display_mode = 0;
2082 static int picker_mode = 0;
2083 ImGui::Checkbox("With Alpha", &alpha);
2084 ImGui::Checkbox("With Alpha Bar", &alpha_bar);
2085 ImGui::Checkbox("With Side Preview", &side_preview);
2086 if (side_preview)
2087 {
2088 ImGui::SameLine();
2089 ImGui::Checkbox("With Ref Color", &ref_color);
2090 if (ref_color)
2091 {
2092 ImGui::SameLine();
2093 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
2094 }
2095 }
2096 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
2097 ImGui::SameLine(); HelpMarker(
2098 "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
2099 "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
2100 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
2101 ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode.");
2102 ImGuiColorEditFlags flags = misc_flags;
2103 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
2104 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
2105 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
2106 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
2107 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
2108 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
2109 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
2110 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
2111 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
2112 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
2113
2114 ImGui::Text("Set defaults in code:");
2115 ImGui::SameLine(); HelpMarker(
2116 "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
2117 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
2118 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
2119 "encouraging you to persistently save values that aren't forward-compatible.");
2120 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
2121 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
2122 if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
2123 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
2124
2125 // Always display a small version of both types of pickers
2126 // (that's in order to make it more visible in the demo to people who are skimming quickly through it)
2127 ImGui::Text("Both types:");
2128 float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f;
2129 ImGui::SetNextItemWidth(w);
2130 ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2131 ImGui::SameLine();
2132 ImGui::SetNextItemWidth(w);
2133 ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha);
2134
2135 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
2136 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
2137 ImGui::Spacing();
2138 ImGui::Text("HSV encoded colors");
2139 ImGui::SameLine(); HelpMarker(
2140 "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
2141 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
2142 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
2143 ImGui::Text("Color widget with InputHSV:");
2144 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2145 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
2146 ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
2147
2148 ImGui::TreePop();
2149 }
2150
2151 IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags");
2152 if (ImGui::TreeNode("Drag/Slider Flags"))
2153 {
2154 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
2155 static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
2156 ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
2157 ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
2158 ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
2159 ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
2160 ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
2161 ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
2162 ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
2163 ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
2164
2165 // Drags
2166 static float drag_f = 0.5f;
2167 static int drag_i = 50;
2168 ImGui::Text("Underlying float value: %f", drag_f);
2169 ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
2170 ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
2171 ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
2172 ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
2173 ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
2174
2175 // Sliders
2176 static float slider_f = 0.5f;
2177 static int slider_i = 50;
2178 ImGui::Text("Underlying float value: %f", slider_f);
2179 ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
2180 ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
2181
2182 ImGui::TreePop();
2183 }
2184
2185 IMGUI_DEMO_MARKER("Widgets/Range Widgets");
2186 if (ImGui::TreeNode("Range Widgets"))
2187 {
2188 static float begin = 10, end = 90;
2189 static int begin_i = 100, end_i = 1000;
2190 ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
2191 ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
2192 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
2193 ImGui::TreePop();
2194 }
2195
2196 IMGUI_DEMO_MARKER("Widgets/Data Types");
2197 if (ImGui::TreeNode("Data Types"))
2198 {
2199 // DragScalar/InputScalar/SliderScalar functions allow various data types
2200 // - signed/unsigned
2201 // - 8/16/32/64-bits
2202 // - integer/float/double
2203 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
2204 // to pass the type, and passing all arguments by pointer.
2205 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type.
2206 // In practice, if you frequently use a given type that is not covered by the normal API entry points,
2207 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
2208 // and then pass their address to the generic function. For example:
2209 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
2210 // {
2211 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
2212 // }
2213
2214 // Setup limits (as helper variables so we can take their address, as explained above)
2215 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
2216 #ifndef LLONG_MIN
2217 ImS64 LLONG_MIN = -9223372036854775807LL - 1;
2218 ImS64 LLONG_MAX = 9223372036854775807LL;
2219 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
2220 #endif
2221 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
2222 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
2223 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
2224 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
2225 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;
2226 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;
2227 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;
2228 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;
2229 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
2230 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
2231
2232 // State
2233 static char s8_v = 127;
2234 static ImU8 u8_v = 255;
2235 static short s16_v = 32767;
2236 static ImU16 u16_v = 65535;
2237 static ImS32 s32_v = -1;
2238 static ImU32 u32_v = (ImU32)-1;
2239 static ImS64 s64_v = -1;
2240 static ImU64 u64_v = (ImU64)-1;
2241 static float f32_v = 0.123f;
2242 static double f64_v = 90000.01234567890123456789;
2243
2244 const float drag_speed = 0.2f;
2245 static bool drag_clamp = false;
2246 IMGUI_DEMO_MARKER("Widgets/Data Types/Drags");
2247 ImGui::SeparatorText("Drags");
2248 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
2249 ImGui::SameLine(); HelpMarker(
2250 "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n"
2251 "You can override the clamping limits by using CTRL+Click to input a value.");
2252 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
2253 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
2254 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
2255 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
2256 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
2257 ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X");
2258 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
2259 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
2260 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
2261 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
2262 ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
2263 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
2264 ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
2265
2266 IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders");
2267 ImGui::SeparatorText("Sliders");
2268 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
2269 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
2270 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
2271 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
2272 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
2273 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
2274 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
2275 ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X");
2276 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
2277 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
2278 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
2279 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
2280 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
2281 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64);
2282 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
2283 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
2284 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms");
2285 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
2286 ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2287 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
2288 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
2289 ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2290 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
2291
2292 ImGui::SeparatorText("Sliders (reverse)");
2293 ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
2294 ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
2295 ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
2296 ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
2297 ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
2298 ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
2299
2300 IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
2301 static bool inputs_step = true;
2302 ImGui::SeparatorText("Inputs");
2303 ImGui::Checkbox("Show step buttons", &inputs_step);
2304 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d");
2305 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u");
2306 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d");
2307 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u");
2308 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
2309 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X");
2310 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
2311 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X");
2312 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL);
2313 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL);
2314 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL);
2315 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL);
2316
2317 ImGui::TreePop();
2318 }
2319
2320 IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets");
2321 if (ImGui::TreeNode("Multi-component Widgets"))
2322 {
2323 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2324 static int vec4i[4] = { 1, 5, 100, 255 };
2325
2326 ImGui::SeparatorText("2-wide");
2327 ImGui::InputFloat2("input float2", vec4f);
2328 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
2329 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
2330 ImGui::InputInt2("input int2", vec4i);
2331 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
2332 ImGui::SliderInt2("slider int2", vec4i, 0, 255);
2333
2334 ImGui::SeparatorText("3-wide");
2335 ImGui::InputFloat3("input float3", vec4f);
2336 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
2337 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
2338 ImGui::InputInt3("input int3", vec4i);
2339 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
2340 ImGui::SliderInt3("slider int3", vec4i, 0, 255);
2341
2342 ImGui::SeparatorText("4-wide");
2343 ImGui::InputFloat4("input float4", vec4f);
2344 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
2345 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
2346 ImGui::InputInt4("input int4", vec4i);
2347 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
2348 ImGui::SliderInt4("slider int4", vec4i, 0, 255);
2349
2350 ImGui::TreePop();
2351 }
2352
2353 IMGUI_DEMO_MARKER("Widgets/Vertical Sliders");
2354 if (ImGui::TreeNode("Vertical Sliders"))
2355 {
2356 const float spacing = 4;
2357 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
2358
2359 static int int_value = 0;
2360 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
2361 ImGui::SameLine();
2362
2363 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
2364 ImGui::PushID("set1");
2365 for (int i = 0; i < 7; i++)
2366 {
2367 if (i > 0) ImGui::SameLine();
2368 ImGui::PushID(i);
2369 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
2370 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
2371 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
2372 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
2373 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
2374 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2375 ImGui::SetTooltip("%.3f", values[i]);
2376 ImGui::PopStyleColor(4);
2377 ImGui::PopID();
2378 }
2379 ImGui::PopID();
2380
2381 ImGui::SameLine();
2382 ImGui::PushID("set2");
2383 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
2384 const int rows = 3;
2385 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
2386 for (int nx = 0; nx < 4; nx++)
2387 {
2388 if (nx > 0) ImGui::SameLine();
2389 ImGui::BeginGroup();
2390 for (int ny = 0; ny < rows; ny++)
2391 {
2392 ImGui::PushID(nx * rows + ny);
2393 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
2394 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2395 ImGui::SetTooltip("%.3f", values2[nx]);
2396 ImGui::PopID();
2397 }
2398 ImGui::EndGroup();
2399 }
2400 ImGui::PopID();
2401
2402 ImGui::SameLine();
2403 ImGui::PushID("set3");
2404 for (int i = 0; i < 4; i++)
2405 {
2406 if (i > 0) ImGui::SameLine();
2407 ImGui::PushID(i);
2408 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
2409 ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
2410 ImGui::PopStyleVar();
2411 ImGui::PopID();
2412 }
2413 ImGui::PopID();
2414 ImGui::PopStyleVar();
2415 ImGui::TreePop();
2416 }
2417
2418 IMGUI_DEMO_MARKER("Widgets/Drag and drop");
2419 if (ImGui::TreeNode("Drag and Drop"))
2420 {
2421 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets");
2422 if (ImGui::TreeNode("Drag and drop in standard widgets"))
2423 {
2424 // ColorEdit widgets automatically act as drag source and drag target.
2425 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
2426 // to allow your own widgets to use colors in their drag and drop interaction.
2427 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
2428 HelpMarker("You can drag from the color squares.");
2429 static float col1[3] = { 1.0f, 0.0f, 0.2f };
2430 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
2431 ImGui::ColorEdit3("color 1", col1);
2432 ImGui::ColorEdit4("color 2", col2);
2433 ImGui::TreePop();
2434 }
2435
2436 IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items");
2437 if (ImGui::TreeNode("Drag and drop to copy/swap items"))
2438 {
2439 enum Mode
2440 {
2441 Mode_Copy,
2442 Mode_Move,
2443 Mode_Swap
2444 };
2445 static int mode = 0;
2446 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
2447 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
2448 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
2449 static const char* names[9] =
2450 {
2451 "Bobby", "Beatrice", "Betty",
2452 "Brianna", "Barry", "Bernard",
2453 "Bibi", "Blaine", "Bryn"
2454 };
2455 for (int n = 0; n < IM_ARRAYSIZE(names); n++)
2456 {
2457 ImGui::PushID(n);
2458 if ((n % 3) != 0)
2459 ImGui::SameLine();
2460 ImGui::Button(names[n], ImVec2(60, 60));
2461
2462 // Our buttons are both drag sources and drag targets here!
2463 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
2464 {
2465 // Set payload to carry the index of our item (could be anything)
2466 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
2467
2468 // Display preview (could be anything, e.g. when dragging an image we could decide to display
2469 // the filename and a small preview of the image, etc.)
2470 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
2471 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
2472 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
2473 ImGui::EndDragDropSource();
2474 }
2475 if (ImGui::BeginDragDropTarget())
2476 {
2477 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
2478 {
2479 IM_ASSERT(payload->DataSize == sizeof(int));
2480 int payload_n = *(const int*)payload->Data;
2481 if (mode == Mode_Copy)
2482 {
2483 names[n] = names[payload_n];
2484 }
2485 if (mode == Mode_Move)
2486 {
2487 names[n] = names[payload_n];
2488 names[payload_n] = "";
2489 }
2490 if (mode == Mode_Swap)
2491 {
2492 const char* tmp = names[n];
2493 names[n] = names[payload_n];
2494 names[payload_n] = tmp;
2495 }
2496 }
2497 ImGui::EndDragDropTarget();
2498 }
2499 ImGui::PopID();
2500 }
2501 ImGui::TreePop();
2502 }
2503
2504 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
2505 if (ImGui::TreeNode("Drag to reorder items (simple)"))
2506 {
2507 // Simple reordering
2508 HelpMarker(
2509 "We don't use the drag and drop api at all here! "
2510 "Instead we query when the item is held but not hovered, and order items accordingly.");
2511 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
2512 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
2513 {
2514 const char* item = item_names[n];
2515 ImGui::Selectable(item);
2516
2517 if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
2518 {
2519 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
2520 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
2521 {
2522 item_names[n] = item_names[n_next];
2523 item_names[n_next] = item;
2524 ImGui::ResetMouseDragDelta();
2525 }
2526 }
2527 }
2528 ImGui::TreePop();
2529 }
2530
2531 IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location");
2532 if (ImGui::TreeNode("Tooltip at target location"))
2533 {
2534 for (int n = 0; n < 2; n++)
2535 {
2536 // Drop targets
2537 ImGui::Button(n ? "drop here##1" : "drop here##0");
2538 if (ImGui::BeginDragDropTarget())
2539 {
2540 ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip;
2541 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags))
2542 {
2543 IM_UNUSED(payload);
2544 ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
2545 ImGui::BeginTooltip();
2546 ImGui::Text("Cannot drop here!");
2547 ImGui::EndTooltip();
2548 }
2549 ImGui::EndDragDropTarget();
2550 }
2551
2552 // Drop source
2553 static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f };
2554 if (n == 0)
2555 ImGui::ColorButton("drag me", col4);
2556
2557 }
2558 ImGui::TreePop();
2559 }
2560
2561 ImGui::TreePop();
2562 }
2563
2564 IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)");
2565 if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)"))
2566 {
2567 // Select an item type
2568 const char* item_names[] =
2569 {
2570 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat",
2571 "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2572 };
2573 static int item_type = 4;
2574 static bool item_disabled = false;
2575 ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
2576 ImGui::SameLine();
2577 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().");
2578 ImGui::Checkbox("Item Disabled", &item_disabled);
2579
2580 // Submit selected items so we can query their status in the code following it.
2581 bool ret = false;
2582 static bool b = false;
2583 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2584 static char str[16] = {};
2585 if (item_disabled)
2586 ImGui::BeginDisabled(true);
2587 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
2588 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
2589 if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
2590 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
2591 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
2592 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
2593 if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window)
2594 if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
2595 if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2596 if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2597 if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
2598 if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2599 if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
2600 if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2601 if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_ARRAYSIZE(items)); }
2602 if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
2603
2604 bool hovered_delay_none = ImGui::IsItemHovered();
2605 bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary);
2606 bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
2607 bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
2608 bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary
2609
2610 // Display the values of IsItemHovered() and other common item state functions.
2611 // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2612 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2613 // we query every state in a single call to avoid storing them and to simplify the code.
2614 ImGui::BulletText(
2615 "Return value = %d\n"
2616 "IsItemFocused() = %d\n"
2617 "IsItemHovered() = %d\n"
2618 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2619 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2620 "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n"
2621 "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n"
2622 "IsItemHovered(_AllowWhenDisabled) = %d\n"
2623 "IsItemHovered(_RectOnly) = %d\n"
2624 "IsItemActive() = %d\n"
2625 "IsItemEdited() = %d\n"
2626 "IsItemActivated() = %d\n"
2627 "IsItemDeactivated() = %d\n"
2628 "IsItemDeactivatedAfterEdit() = %d\n"
2629 "IsItemVisible() = %d\n"
2630 "IsItemClicked() = %d\n"
2631 "IsItemToggledOpen() = %d\n"
2632 "GetItemRectMin() = (%.1f, %.1f)\n"
2633 "GetItemRectMax() = (%.1f, %.1f)\n"
2634 "GetItemRectSize() = (%.1f, %.1f)",
2635 ret,
2636 ImGui::IsItemFocused(),
2637 ImGui::IsItemHovered(),
2638 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2639 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2640 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem),
2641 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow),
2642 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled),
2643 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2644 ImGui::IsItemActive(),
2645 ImGui::IsItemEdited(),
2646 ImGui::IsItemActivated(),
2647 ImGui::IsItemDeactivated(),
2648 ImGui::IsItemDeactivatedAfterEdit(),
2649 ImGui::IsItemVisible(),
2650 ImGui::IsItemClicked(),
2651 ImGui::IsItemToggledOpen(),
2652 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2653 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2654 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2655 );
2656 ImGui::BulletText(
2657 "with Hovering Delay or Stationary test:\n"
2658 "IsItemHovered() = = %d\n"
2659 "IsItemHovered(_Stationary) = %d\n"
2660 "IsItemHovered(_DelayShort) = %d\n"
2661 "IsItemHovered(_DelayNormal) = %d\n"
2662 "IsItemHovered(_Tooltip) = %d",
2663 hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip);
2664
2665 if (item_disabled)
2666 ImGui::EndDisabled();
2667
2668 char buf[1] = "";
2669 ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly);
2670 ImGui::SameLine();
2671 HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status.");
2672
2673 ImGui::TreePop();
2674 }
2675
2676 IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)");
2677 if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)"))
2678 {
2679 static bool embed_all_inside_a_child_window = false;
2680 ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
2681 if (embed_all_inside_a_child_window)
2682 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Border);
2683
2684 // Testing IsWindowFocused() function with its various flags.
2685 ImGui::BulletText(
2686 "IsWindowFocused() = %d\n"
2687 "IsWindowFocused(_ChildWindows) = %d\n"
2688 "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n"
2689 "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n"
2690 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2691 "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2692 "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2693 "IsWindowFocused(_RootWindow) = %d\n"
2694 "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n"
2695 "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
2696 "IsWindowFocused(_AnyWindow) = %d\n",
2697 ImGui::IsWindowFocused(),
2698 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2699 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy),
2700 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy),
2701 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2702 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2703 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2704 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2705 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy),
2706 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
2707 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2708
2709 // Testing IsWindowHovered() function with its various flags.
2710 ImGui::BulletText(
2711 "IsWindowHovered() = %d\n"
2712 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2713 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2714 "IsWindowHovered(_ChildWindows) = %d\n"
2715 "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n"
2716 "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n"
2717 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2718 "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n"
2719 "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
2720 "IsWindowHovered(_RootWindow) = %d\n"
2721 "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n"
2722 "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
2723 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2724 "IsWindowHovered(_AnyWindow) = %d\n"
2725 "IsWindowHovered(_Stationary) = %d\n",
2726 ImGui::IsWindowHovered(),
2727 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2728 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2729 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2730 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy),
2731 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy),
2732 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2733 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2734 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2735 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2736 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy),
2737 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
2738 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2739 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
2740 ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
2741
2742 ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Border);
2743 ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2744 ImGui::EndChild();
2745 if (embed_all_inside_a_child_window)
2746 ImGui::EndChild();
2747
2748 // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2749 // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2750 // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2751 static bool test_window = false;
2752 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2753 if (test_window)
2754 {
2755 // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2756 // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2757 ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2758 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2759 {
2760 if (ImGui::MenuItem("Close")) { test_window = false; }
2761 ImGui::EndPopup();
2762 }
2763 ImGui::Text(
2764 "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2765 "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2766 ImGui::IsItemHovered(), ImGui::IsItemActive());
2767 ImGui::End();
2768 }
2769
2770 ImGui::TreePop();
2771 }
2772
2773 // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd:
2774 // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space)
2775 if (disable_all)
2776 ImGui::EndDisabled();
2777
2778 IMGUI_DEMO_MARKER("Widgets/Disable Block");
2779 if (ImGui::TreeNode("Disable block"))
2780 {
2781 ImGui::Checkbox("Disable entire section above", &disable_all);
2782 ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section.");
2783 ImGui::TreePop();
2784 }
2785
2786 IMGUI_DEMO_MARKER("Widgets/Text Filter");
2787 if (ImGui::TreeNode("Text Filter"))
2788 {
2789 // Helper class to easy setup a text filter.
2790 // You may want to implement a more feature-full filtering scheme in your own application.
2791 HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
2792 static ImGuiTextFilter filter;
2793 ImGui::Text("Filter usage:\n"
2794 " \"\" display all lines\n"
2795 " \"xxx\" display lines containing \"xxx\"\n"
2796 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
2797 " \"-xxx\" hide lines containing \"xxx\"");
2798 filter.Draw();
2799 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
2800 for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
2801 if (filter.PassFilter(lines[i]))
2802 ImGui::BulletText("%s", lines[i]);
2803 ImGui::TreePop();
2804 }
2805}
2806
2807static void ShowDemoWindowLayout()
2808{
2809 IMGUI_DEMO_MARKER("Layout");
2810 if (!ImGui::CollapsingHeader("Layout & Scrolling"))
2811 return;
2812
2813 IMGUI_DEMO_MARKER("Layout/Child windows");
2814 if (ImGui::TreeNode("Child windows"))
2815 {
2816 ImGui::SeparatorText("Child windows");
2817
2818 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
2819 static bool disable_mouse_wheel = false;
2820 static bool disable_menu = false;
2821 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
2822 ImGui::Checkbox("Disable Menu", &disable_menu);
2823
2824 // Child 1: no border, enable horizontal scrollbar
2825 {
2826 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
2827 if (disable_mouse_wheel)
2828 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2829 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), ImGuiChildFlags_None, window_flags);
2830 for (int i = 0; i < 100; i++)
2831 ImGui::Text("%04d: scrollable region", i);
2832 ImGui::EndChild();
2833 }
2834
2835 ImGui::SameLine();
2836
2837 // Child 2: rounded border
2838 {
2839 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
2840 if (disable_mouse_wheel)
2841 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2842 if (!disable_menu)
2843 window_flags |= ImGuiWindowFlags_MenuBar;
2844 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
2845 ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Border, window_flags);
2846 if (!disable_menu && ImGui::BeginMenuBar())
2847 {
2848 if (ImGui::BeginMenu("Menu"))
2849 {
2850 ShowExampleMenuFile();
2851 ImGui::EndMenu();
2852 }
2853 ImGui::EndMenuBar();
2854 }
2855 if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
2856 {
2857 for (int i = 0; i < 100; i++)
2858 {
2859 char buf[32];
2860 sprintf(buf, "%03d", i);
2861 ImGui::TableNextColumn();
2862 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
2863 }
2864 ImGui::EndTable();
2865 }
2866 ImGui::EndChild();
2867 ImGui::PopStyleVar();
2868 }
2869
2870 // Child 3: manual-resize
2871 ImGui::SeparatorText("Manual-resize");
2872 {
2873 HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
2874 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
2875 if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY))
2876 for (int n = 0; n < 10; n++)
2877 ImGui::Text("Line %04d", n);
2878 ImGui::PopStyleColor();
2879 ImGui::EndChild();
2880 }
2881
2882 // Child 4: auto-resizing height with a limit
2883 ImGui::SeparatorText("Auto-resize with constraints");
2884 {
2885 static int draw_lines = 3;
2886 static int max_height_in_lines = 10;
2887 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2888 ImGui::DragInt("Lines Count", &draw_lines, 0.2f);
2889 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2890 ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
2891
2892 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
2893 if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY))
2894 for (int n = 0; n < draw_lines; n++)
2895 ImGui::Text("Line %04d", n);
2896 ImGui::EndChild();
2897 }
2898
2899 ImGui::SeparatorText("Misc/Advanced");
2900
2901 // Demonstrate a few extra things
2902 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
2903 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
2904 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively
2905 // layout from this position.
2906 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
2907 // the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
2908 {
2909 static int offset_x = 0;
2910 static bool override_bg_color = true;
2911 static ImGuiChildFlags child_flags = ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
2912 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2913 ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
2914 ImGui::Checkbox("Override ChildBg color", &override_bg_color);
2915 ImGui::CheckboxFlags("ImGuiChildFlags_Border", &child_flags, ImGuiChildFlags_Border);
2916 ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
2917 ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
2918 ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
2919 ImGui::CheckboxFlags("ImGuiChildFlags_FrameStyle", &child_flags, ImGuiChildFlags_FrameStyle);
2920 ImGui::SameLine(); HelpMarker("Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.");
2921 if (child_flags & ImGuiChildFlags_FrameStyle)
2922 override_bg_color = false;
2923
2924 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
2925 if (override_bg_color)
2926 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
2927 ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
2928 if (override_bg_color)
2929 ImGui::PopStyleColor();
2930
2931 for (int n = 0; n < 50; n++)
2932 ImGui::Text("Some test %d", n);
2933 ImGui::EndChild();
2934 bool child_is_hovered = ImGui::IsItemHovered();
2935 ImVec2 child_rect_min = ImGui::GetItemRectMin();
2936 ImVec2 child_rect_max = ImGui::GetItemRectMax();
2937 ImGui::Text("Hovered: %d", child_is_hovered);
2938 ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y);
2939 }
2940
2941 ImGui::TreePop();
2942 }
2943
2944 IMGUI_DEMO_MARKER("Layout/Widgets Width");
2945 if (ImGui::TreeNode("Widgets Width"))
2946 {
2947 static float f = 0.0f;
2948 static bool show_indented_items = true;
2949 ImGui::Checkbox("Show indented items", &show_indented_items);
2950
2951 // Use SetNextItemWidth() to set the width of a single upcoming item.
2952 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
2953 // In real code use you'll probably want to choose width values that are proportional to your font size
2954 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
2955
2956 ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
2957 ImGui::SameLine(); HelpMarker("Fixed width.");
2958 ImGui::PushItemWidth(100);
2959 ImGui::DragFloat("float##1b", &f);
2960 if (show_indented_items)
2961 {
2962 ImGui::Indent();
2963 ImGui::DragFloat("float (indented)##1b", &f);
2964 ImGui::Unindent();
2965 }
2966 ImGui::PopItemWidth();
2967
2968 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
2969 ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
2970 ImGui::PushItemWidth(-100);
2971 ImGui::DragFloat("float##2a", &f);
2972 if (show_indented_items)
2973 {
2974 ImGui::Indent();
2975 ImGui::DragFloat("float (indented)##2b", &f);
2976 ImGui::Unindent();
2977 }
2978 ImGui::PopItemWidth();
2979
2980 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
2981 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
2982 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
2983 ImGui::DragFloat("float##3a", &f);
2984 if (show_indented_items)
2985 {
2986 ImGui::Indent();
2987 ImGui::DragFloat("float (indented)##3b", &f);
2988 ImGui::Unindent();
2989 }
2990 ImGui::PopItemWidth();
2991
2992 ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
2993 ImGui::SameLine(); HelpMarker("Align to right edge minus half");
2994 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
2995 ImGui::DragFloat("float##4a", &f);
2996 if (show_indented_items)
2997 {
2998 ImGui::Indent();
2999 ImGui::DragFloat("float (indented)##4b", &f);
3000 ImGui::Unindent();
3001 }
3002 ImGui::PopItemWidth();
3003
3004 // Demonstrate using PushItemWidth to surround three items.
3005 // Calling SetNextItemWidth() before each of them would have the same effect.
3006 ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
3007 ImGui::SameLine(); HelpMarker("Align to right edge");
3008 ImGui::PushItemWidth(-FLT_MIN);
3009 ImGui::DragFloat("##float5a", &f);
3010 if (show_indented_items)
3011 {
3012 ImGui::Indent();
3013 ImGui::DragFloat("float (indented)##5b", &f);
3014 ImGui::Unindent();
3015 }
3016 ImGui::PopItemWidth();
3017
3018 ImGui::TreePop();
3019 }
3020
3021 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout");
3022 if (ImGui::TreeNode("Basic Horizontal Layout"))
3023 {
3024 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
3025
3026 // Text
3027 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine");
3028 ImGui::Text("Two items: Hello"); ImGui::SameLine();
3029 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
3030
3031 // Adjust spacing
3032 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
3033 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
3034
3035 // Button
3036 ImGui::AlignTextToFramePadding();
3037 ImGui::Text("Normal buttons"); ImGui::SameLine();
3038 ImGui::Button("Banana"); ImGui::SameLine();
3039 ImGui::Button("Apple"); ImGui::SameLine();
3040 ImGui::Button("Corniflower");
3041
3042 // Button
3043 ImGui::Text("Small buttons"); ImGui::SameLine();
3044 ImGui::SmallButton("Like this one"); ImGui::SameLine();
3045 ImGui::Text("can fit within a text block.");
3046
3047 // Aligned to arbitrary position. Easy/cheap column.
3048 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (with offset)");
3049 ImGui::Text("Aligned");
3050 ImGui::SameLine(150); ImGui::Text("x=150");
3051 ImGui::SameLine(300); ImGui::Text("x=300");
3052 ImGui::Text("Aligned");
3053 ImGui::SameLine(150); ImGui::SmallButton("x=150");
3054 ImGui::SameLine(300); ImGui::SmallButton("x=300");
3055
3056 // Checkbox
3057 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/SameLine (more)");
3058 static bool c1 = false, c2 = false, c3 = false, c4 = false;
3059 ImGui::Checkbox("My", &c1); ImGui::SameLine();
3060 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
3061 ImGui::Checkbox("Is", &c3); ImGui::SameLine();
3062 ImGui::Checkbox("Rich", &c4);
3063
3064 // Various
3065 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
3066 ImGui::PushItemWidth(80);
3067 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
3068 static int item = -1;
3069 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
3070 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
3071 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
3072 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
3073 ImGui::PopItemWidth();
3074
3075 ImGui::PushItemWidth(80);
3076 ImGui::Text("Lists:");
3077 static int selection[4] = { 0, 1, 2, 3 };
3078 for (int i = 0; i < 4; i++)
3079 {
3080 if (i > 0) ImGui::SameLine();
3081 ImGui::PushID(i);
3082 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
3083 ImGui::PopID();
3084 //ImGui::SetItemTooltip("ListBox %d hovered", i);
3085 }
3086 ImGui::PopItemWidth();
3087
3088 // Dummy
3089 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Dummy");
3090 ImVec2 button_sz(40, 40);
3091 ImGui::Button("A", button_sz); ImGui::SameLine();
3092 ImGui::Dummy(button_sz); ImGui::SameLine();
3093 ImGui::Button("B", button_sz);
3094
3095 // Manually wrapping
3096 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
3097 IMGUI_DEMO_MARKER("Layout/Basic Horizontal Layout/Manual wrapping");
3098 ImGui::Text("Manual wrapping:");
3099 ImGuiStyle& style = ImGui::GetStyle();
3100 int buttons_count = 20;
3101 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
3102 for (int n = 0; n < buttons_count; n++)
3103 {
3104 ImGui::PushID(n);
3105 ImGui::Button("Box", button_sz);
3106 float last_button_x2 = ImGui::GetItemRectMax().x;
3107 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
3108 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
3109 ImGui::SameLine();
3110 ImGui::PopID();
3111 }
3112
3113 ImGui::TreePop();
3114 }
3115
3116 IMGUI_DEMO_MARKER("Layout/Groups");
3117 if (ImGui::TreeNode("Groups"))
3118 {
3119 HelpMarker(
3120 "BeginGroup() basically locks the horizontal position for new line. "
3121 "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
3122 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
3123 ImGui::BeginGroup();
3124 {
3125 ImGui::BeginGroup();
3126 ImGui::Button("AAA");
3127 ImGui::SameLine();
3128 ImGui::Button("BBB");
3129 ImGui::SameLine();
3130 ImGui::BeginGroup();
3131 ImGui::Button("CCC");
3132 ImGui::Button("DDD");
3133 ImGui::EndGroup();
3134 ImGui::SameLine();
3135 ImGui::Button("EEE");
3136 ImGui::EndGroup();
3137 ImGui::SetItemTooltip("First group hovered");
3138 }
3139 // Capture the group size and create widgets using the same size
3140 ImVec2 size = ImGui::GetItemRectSize();
3141 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
3142 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
3143
3144 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
3145 ImGui::SameLine();
3146 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
3147 ImGui::EndGroup();
3148 ImGui::SameLine();
3149
3150 ImGui::Button("LEVERAGE\nBUZZWORD", size);
3151 ImGui::SameLine();
3152
3153 if (ImGui::BeginListBox("List", size))
3154 {
3155 ImGui::Selectable("Selected", true);
3156 ImGui::Selectable("Not Selected", false);
3157 ImGui::EndListBox();
3158 }
3159
3160 ImGui::TreePop();
3161 }
3162
3163 IMGUI_DEMO_MARKER("Layout/Text Baseline Alignment");
3164 if (ImGui::TreeNode("Text Baseline Alignment"))
3165 {
3166 {
3167 ImGui::BulletText("Text baseline:");
3168 ImGui::SameLine(); HelpMarker(
3169 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
3170 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
3171 ImGui::Indent();
3172
3173 ImGui::Text("KO Blahblah"); ImGui::SameLine();
3174 ImGui::Button("Some framed item"); ImGui::SameLine();
3175 HelpMarker("Baseline of button will look misaligned with text..");
3176
3177 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
3178 // (because we don't know what's coming after the Text() statement, we need to move the text baseline
3179 // down by FramePadding.y ahead of time)
3180 ImGui::AlignTextToFramePadding();
3181 ImGui::Text("OK Blahblah"); ImGui::SameLine();
3182 ImGui::Button("Some framed item"); ImGui::SameLine();
3183 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
3184
3185 // SmallButton() uses the same vertical padding as Text
3186 ImGui::Button("TEST##1"); ImGui::SameLine();
3187 ImGui::Text("TEST"); ImGui::SameLine();
3188 ImGui::SmallButton("TEST##2");
3189
3190 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
3191 ImGui::AlignTextToFramePadding();
3192 ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
3193 ImGui::Button("Item##1"); ImGui::SameLine();
3194 ImGui::Text("Item"); ImGui::SameLine();
3195 ImGui::SmallButton("Item##2"); ImGui::SameLine();
3196 ImGui::Button("Item##3");
3197
3198 ImGui::Unindent();
3199 }
3200
3201 ImGui::Spacing();
3202
3203 {
3204 ImGui::BulletText("Multi-line text:");
3205 ImGui::Indent();
3206 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
3207 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
3208 ImGui::Text("Banana");
3209
3210 ImGui::Text("Banana"); ImGui::SameLine();
3211 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
3212 ImGui::Text("One\nTwo\nThree");
3213
3214 ImGui::Button("HOP##1"); ImGui::SameLine();
3215 ImGui::Text("Banana"); ImGui::SameLine();
3216 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
3217 ImGui::Text("Banana");
3218
3219 ImGui::Button("HOP##2"); ImGui::SameLine();
3220 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
3221 ImGui::Text("Banana");
3222 ImGui::Unindent();
3223 }
3224
3225 ImGui::Spacing();
3226
3227 {
3228 ImGui::BulletText("Misc items:");
3229 ImGui::Indent();
3230
3231 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
3232 ImGui::Button("80x80", ImVec2(80, 80));
3233 ImGui::SameLine();
3234 ImGui::Button("50x50", ImVec2(50, 50));
3235 ImGui::SameLine();
3236 ImGui::Button("Button()");
3237 ImGui::SameLine();
3238 ImGui::SmallButton("SmallButton()");
3239
3240 // Tree
3241 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
3242 ImGui::Button("Button##1");
3243 ImGui::SameLine(0.0f, spacing);
3244 if (ImGui::TreeNode("Node##1"))
3245 {
3246 // Placeholder tree data
3247 for (int i = 0; i < 6; i++)
3248 ImGui::BulletText("Item %d..", i);
3249 ImGui::TreePop();
3250 }
3251
3252 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
3253 // Otherwise you can use SmallButton() (smaller fit).
3254 ImGui::AlignTextToFramePadding();
3255
3256 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
3257 // other contents below the node.
3258 bool node_open = ImGui::TreeNode("Node##2");
3259 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
3260 if (node_open)
3261 {
3262 // Placeholder tree data
3263 for (int i = 0; i < 6; i++)
3264 ImGui::BulletText("Item %d..", i);
3265 ImGui::TreePop();
3266 }
3267
3268 // Bullet
3269 ImGui::Button("Button##3");
3270 ImGui::SameLine(0.0f, spacing);
3271 ImGui::BulletText("Bullet text");
3272
3273 ImGui::AlignTextToFramePadding();
3274 ImGui::BulletText("Node");
3275 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
3276 ImGui::Unindent();
3277 }
3278
3279 ImGui::TreePop();
3280 }
3281
3282 IMGUI_DEMO_MARKER("Layout/Scrolling");
3283 if (ImGui::TreeNode("Scrolling"))
3284 {
3285 // Vertical scroll functions
3286 IMGUI_DEMO_MARKER("Layout/Scrolling/Vertical");
3287 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
3288
3289 static int track_item = 50;
3290 static bool enable_track = true;
3291 static bool enable_extra_decorations = false;
3292 static float scroll_to_off_px = 0.0f;
3293 static float scroll_to_pos_px = 200.0f;
3294
3295 ImGui::Checkbox("Decoration", &enable_extra_decorations);
3296
3297 ImGui::Checkbox("Track", &enable_track);
3298 ImGui::PushItemWidth(100);
3299 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
3300
3301 bool scroll_to_off = ImGui::Button("Scroll Offset");
3302 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
3303
3304 bool scroll_to_pos = ImGui::Button("Scroll To Pos");
3305 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
3306 ImGui::PopItemWidth();
3307
3308 if (scroll_to_off || scroll_to_pos)
3309 enable_track = false;
3310
3311 ImGuiStyle& style = ImGui::GetStyle();
3312 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
3313 if (child_w < 1.0f)
3314 child_w = 1.0f;
3315 ImGui::PushID("##VerticalScrolling");
3316 for (int i = 0; i < 5; i++)
3317 {
3318 if (i > 0) ImGui::SameLine();
3319 ImGui::BeginGroup();
3320 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
3321 ImGui::TextUnformatted(names[i]);
3322
3323 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
3324 const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
3325 const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Border, child_flags);
3326 if (ImGui::BeginMenuBar())
3327 {
3329 ImGui::EndMenuBar();
3330 }
3331 if (scroll_to_off)
3332 ImGui::SetScrollY(scroll_to_off_px);
3333 if (scroll_to_pos)
3334 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
3335 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
3336 {
3337 for (int item = 0; item < 100; item++)
3338 {
3339 if (enable_track && item == track_item)
3340 {
3341 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
3342 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
3343 }
3344 else
3345 {
3346 ImGui::Text("Item %d", item);
3347 }
3348 }
3349 }
3350 float scroll_y = ImGui::GetScrollY();
3351 float scroll_max_y = ImGui::GetScrollMaxY();
3352 ImGui::EndChild();
3353 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
3354 ImGui::EndGroup();
3355 }
3356 ImGui::PopID();
3357
3358 // Horizontal scroll functions
3359 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal");
3360 ImGui::Spacing();
3361 HelpMarker(
3362 "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
3363 "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
3364 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
3365 "equivalent SetScrollFromPosY(+1) wouldn't.");
3366 ImGui::PushID("##HorizontalScrolling");
3367 for (int i = 0; i < 5; i++)
3368 {
3369 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
3370 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
3371 ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
3372 bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Border, child_flags);
3373 if (scroll_to_off)
3374 ImGui::SetScrollX(scroll_to_off_px);
3375 if (scroll_to_pos)
3376 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
3377 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
3378 {
3379 for (int item = 0; item < 100; item++)
3380 {
3381 if (item > 0)
3382 ImGui::SameLine();
3383 if (enable_track && item == track_item)
3384 {
3385 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
3386 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
3387 }
3388 else
3389 {
3390 ImGui::Text("Item %d", item);
3391 }
3392 }
3393 }
3394 float scroll_x = ImGui::GetScrollX();
3395 float scroll_max_x = ImGui::GetScrollMaxX();
3396 ImGui::EndChild();
3397 ImGui::SameLine();
3398 const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
3399 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
3400 ImGui::Spacing();
3401 }
3402 ImGui::PopID();
3403
3404 // Miscellaneous Horizontal Scrolling Demo
3405 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal (more)");
3406 HelpMarker(
3407 "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
3408 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
3409 static int lines = 7;
3410 ImGui::SliderInt("Lines", &lines, 1, 15);
3411 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
3412 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
3413 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
3414 ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Border, ImGuiWindowFlags_HorizontalScrollbar);
3415 for (int line = 0; line < lines; line++)
3416 {
3417 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
3418 // If you want to create your own time line for a real application you may be better off manipulating
3419 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
3420 // yourself. You may also want to use the lower-level ImDrawList API.
3421 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
3422 for (int n = 0; n < num_buttons; n++)
3423 {
3424 if (n > 0) ImGui::SameLine();
3425 ImGui::PushID(n + line * 1000);
3426 char num_buf[16];
3427 sprintf(num_buf, "%d", n);
3428 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
3429 float hue = n * 0.05f;
3430 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
3431 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
3432 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
3433 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
3434 ImGui::PopStyleColor(3);
3435 ImGui::PopID();
3436 }
3437 }
3438 float scroll_x = ImGui::GetScrollX();
3439 float scroll_max_x = ImGui::GetScrollMaxX();
3440 ImGui::EndChild();
3441 ImGui::PopStyleVar(2);
3442 float scroll_x_delta = 0.0f;
3443 ImGui::SmallButton("<<");
3444 if (ImGui::IsItemActive())
3445 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
3446 ImGui::SameLine();
3447 ImGui::Text("Scroll from code"); ImGui::SameLine();
3448 ImGui::SmallButton(">>");
3449 if (ImGui::IsItemActive())
3450 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
3451 ImGui::SameLine();
3452 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
3453 if (scroll_x_delta != 0.0f)
3454 {
3455 // Demonstrate a trick: you can use Begin to set yourself in the context of another window
3456 // (here we are already out of your child window)
3457 ImGui::BeginChild("scrolling");
3458 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
3459 ImGui::EndChild();
3460 }
3461 ImGui::Spacing();
3462
3463 static bool show_horizontal_contents_size_demo_window = false;
3464 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
3465
3466 if (show_horizontal_contents_size_demo_window)
3467 {
3468 static bool show_h_scrollbar = true;
3469 static bool show_button = true;
3470 static bool show_tree_nodes = true;
3471 static bool show_text_wrapped = false;
3472 static bool show_columns = true;
3473 static bool show_tab_bar = true;
3474 static bool show_child = false;
3475 static bool explicit_content_size = false;
3476 static float contents_size_x = 300.0f;
3477 if (explicit_content_size)
3478 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
3479 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
3480 IMGUI_DEMO_MARKER("Layout/Scrolling/Horizontal contents size demo window");
3481 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
3482 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
3483 HelpMarker(
3484 "Test how different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\n"
3485 "Use 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
3486 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
3487 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten)
3488 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width
3489 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
3490 ImGui::Checkbox("Columns", &show_columns); // Will use contents size
3491 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size
3492 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size
3493 ImGui::Checkbox("Explicit content size", &explicit_content_size);
3494 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
3495 if (explicit_content_size)
3496 {
3497 ImGui::SameLine();
3498 ImGui::SetNextItemWidth(100);
3499 ImGui::DragFloat("##csx", &contents_size_x);
3500 ImVec2 p = ImGui::GetCursorScreenPos();
3501 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
3502 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
3503 ImGui::Dummy(ImVec2(0, 10));
3504 }
3505 ImGui::PopStyleVar(2);
3506 ImGui::Separator();
3507 if (show_button)
3508 {
3509 ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
3510 }
3511 if (show_tree_nodes)
3512 {
3513 bool open = true;
3514 if (ImGui::TreeNode("this is a tree node"))
3515 {
3516 if (ImGui::TreeNode("another one of those tree node..."))
3517 {
3518 ImGui::Text("Some tree contents");
3519 ImGui::TreePop();
3520 }
3521 ImGui::TreePop();
3522 }
3523 ImGui::CollapsingHeader("CollapsingHeader", &open);
3524 }
3525 if (show_text_wrapped)
3526 {
3527 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
3528 }
3529 if (show_columns)
3530 {
3531 ImGui::Text("Tables:");
3532 if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
3533 {
3534 for (int n = 0; n < 4; n++)
3535 {
3536 ImGui::TableNextColumn();
3537 ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
3538 }
3539 ImGui::EndTable();
3540 }
3541 ImGui::Text("Columns:");
3542 ImGui::Columns(4);
3543 for (int n = 0; n < 4; n++)
3544 {
3545 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
3546 ImGui::NextColumn();
3547 }
3548 ImGui::Columns(1);
3549 }
3550 if (show_tab_bar && ImGui::BeginTabBar("Hello"))
3551 {
3552 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
3553 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
3554 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
3555 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
3556 ImGui::EndTabBar();
3557 }
3558 if (show_child)
3559 {
3560 ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Border);
3561 ImGui::EndChild();
3562 }
3563 ImGui::End();
3564 }
3565
3566 ImGui::TreePop();
3567 }
3568
3569 IMGUI_DEMO_MARKER("Layout/Clipping");
3570 if (ImGui::TreeNode("Clipping"))
3571 {
3572 static ImVec2 size(100.0f, 100.0f);
3573 static ImVec2 offset(30.0f, 30.0f);
3574 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
3575 ImGui::TextWrapped("(Click and drag to scroll)");
3576
3577 HelpMarker(
3578 "(Left) Using ImGui::PushClipRect():\n"
3579 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
3580 "(use this if you want your clipping rectangle to affect interactions)\n\n"
3581 "(Center) Using ImDrawList::PushClipRect():\n"
3582 "Will alter ImDrawList rendering only.\n"
3583 "(use this as a shortcut if you are only using ImDrawList calls)\n\n"
3584 "(Right) Using ImDrawList::AddText() with a fine ClipRect:\n"
3585 "Will alter only this specific ImDrawList::AddText() rendering.\n"
3586 "This is often used internally to avoid altering the clipping rectangle and minimize draw calls.");
3587
3588 for (int n = 0; n < 3; n++)
3589 {
3590 if (n > 0)
3591 ImGui::SameLine();
3592
3593 ImGui::PushID(n);
3594 ImGui::InvisibleButton("##canvas", size);
3595 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
3596 {
3597 offset.x += ImGui::GetIO().MouseDelta.x;
3598 offset.y += ImGui::GetIO().MouseDelta.y;
3599 }
3600 ImGui::PopID();
3601 if (!ImGui::IsItemVisible()) // Skip rendering as ImDrawList elements are not clipped.
3602 continue;
3603
3604 const ImVec2 p0 = ImGui::GetItemRectMin();
3605 const ImVec2 p1 = ImGui::GetItemRectMax();
3606 const char* text_str = "Line 1 hello\nLine 2 clip me!";
3607 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
3608 ImDrawList* draw_list = ImGui::GetWindowDrawList();
3609 switch (n)
3610 {
3611 case 0:
3612 ImGui::PushClipRect(p0, p1, true);
3613 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
3614 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
3615 ImGui::PopClipRect();
3616 break;
3617 case 1:
3618 draw_list->PushClipRect(p0, p1, true);
3619 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
3620 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
3621 draw_list->PopClipRect();
3622 break;
3623 case 2:
3624 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
3625 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
3626 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
3627 break;
3628 }
3629 }
3630
3631 ImGui::TreePop();
3632 }
3633
3634 IMGUI_DEMO_MARKER("Layout/Overlap Mode");
3635 if (ImGui::TreeNode("Overlap Mode"))
3636 {
3637 static bool enable_allow_overlap = true;
3638
3639 HelpMarker(
3640 "Hit-testing is by default performed in item submission order, which generally is perceived as 'back-to-front'.\n\n"
3641 "By using SetNextItemAllowOverlap() you can notify that an item may be overlapped by another. "
3642 "Doing so alters the hovering logic: items using AllowOverlap mode requires an extra frame to accept hovered state.");
3643 ImGui::Checkbox("Enable AllowOverlap", &enable_allow_overlap);
3644
3645 ImVec2 button1_pos = ImGui::GetCursorScreenPos();
3646 ImVec2 button2_pos = ImVec2(button1_pos.x + 50.0f, button1_pos.y + 50.0f);
3647 if (enable_allow_overlap)
3648 ImGui::SetNextItemAllowOverlap();
3649 ImGui::Button("Button 1", ImVec2(80, 80));
3650 ImGui::SetCursorScreenPos(button2_pos);
3651 ImGui::Button("Button 2", ImVec2(80, 80));
3652
3653 // This is typically used with width-spanning items.
3654 // (note that Selectable() has a dedicated flag ImGuiSelectableFlags_AllowOverlap, which is a shortcut
3655 // for using SetNextItemAllowOverlap(). For demo purpose we use SetNextItemAllowOverlap() here.)
3656 if (enable_allow_overlap)
3657 ImGui::SetNextItemAllowOverlap();
3658 ImGui::Selectable("Some Selectable", false);
3659 ImGui::SameLine();
3660 ImGui::SmallButton("++");
3661
3662 ImGui::TreePop();
3663 }
3664}
3665
3666static void ShowDemoWindowPopups()
3667{
3668 IMGUI_DEMO_MARKER("Popups");
3669 if (!ImGui::CollapsingHeader("Popups & Modal windows"))
3670 return;
3671
3672 // The properties of popups windows are:
3673 // - They block normal mouse hovering detection outside them. (*)
3674 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
3675 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
3676 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
3677 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
3678 // when normally blocked by a popup.
3679 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
3680 // popups at any time.
3681
3682 // Typical use for regular windows:
3683 // 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();
3684 // Typical use for popups:
3685 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
3686
3687 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
3688 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
3689
3690 IMGUI_DEMO_MARKER("Popups/Popups");
3691 if (ImGui::TreeNode("Popups"))
3692 {
3693 ImGui::TextWrapped(
3694 "When a popup is active, it inhibits interacting with windows that are behind the popup. "
3695 "Clicking outside the popup closes it.");
3696
3697 static int selected_fish = -1;
3698 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
3699 static bool toggles[] = { true, false, false, false, false };
3700
3701 // Simple selection popup (if you want to show the current selection inside the Button itself,
3702 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
3703 if (ImGui::Button("Select.."))
3704 ImGui::OpenPopup("my_select_popup");
3705 ImGui::SameLine();
3706 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
3707 if (ImGui::BeginPopup("my_select_popup"))
3708 {
3709 ImGui::SeparatorText("Aquarium");
3710 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3711 if (ImGui::Selectable(names[i]))
3712 selected_fish = i;
3713 ImGui::EndPopup();
3714 }
3715
3716 // Showing a menu with toggles
3717 if (ImGui::Button("Toggle.."))
3718 ImGui::OpenPopup("my_toggle_popup");
3719 if (ImGui::BeginPopup("my_toggle_popup"))
3720 {
3721 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3722 ImGui::MenuItem(names[i], "", &toggles[i]);
3723 if (ImGui::BeginMenu("Sub-menu"))
3724 {
3725 ImGui::MenuItem("Click me");
3726 ImGui::EndMenu();
3727 }
3728
3729 ImGui::Separator();
3730 ImGui::Text("Tooltip here");
3731 ImGui::SetItemTooltip("I am a tooltip over a popup");
3732
3733 if (ImGui::Button("Stacked Popup"))
3734 ImGui::OpenPopup("another popup");
3735 if (ImGui::BeginPopup("another popup"))
3736 {
3737 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3738 ImGui::MenuItem(names[i], "", &toggles[i]);
3739 if (ImGui::BeginMenu("Sub-menu"))
3740 {
3741 ImGui::MenuItem("Click me");
3742 if (ImGui::Button("Stacked Popup"))
3743 ImGui::OpenPopup("another popup");
3744 if (ImGui::BeginPopup("another popup"))
3745 {
3746 ImGui::Text("I am the last one here.");
3747 ImGui::EndPopup();
3748 }
3749 ImGui::EndMenu();
3750 }
3751 ImGui::EndPopup();
3752 }
3753 ImGui::EndPopup();
3754 }
3755
3756 // Call the more complete ShowExampleMenuFile which we use in various places of this demo
3757 if (ImGui::Button("With a menu.."))
3758 ImGui::OpenPopup("my_file_popup");
3759 if (ImGui::BeginPopup("my_file_popup", ImGuiWindowFlags_MenuBar))
3760 {
3761 if (ImGui::BeginMenuBar())
3762 {
3763 if (ImGui::BeginMenu("File"))
3764 {
3765 ShowExampleMenuFile();
3766 ImGui::EndMenu();
3767 }
3768 if (ImGui::BeginMenu("Edit"))
3769 {
3770 ImGui::MenuItem("Dummy");
3771 ImGui::EndMenu();
3772 }
3773 ImGui::EndMenuBar();
3774 }
3775 ImGui::Text("Hello from popup!");
3776 ImGui::Button("This is a dummy button..");
3777 ImGui::EndPopup();
3778 }
3779
3780 ImGui::TreePop();
3781 }
3782
3783 IMGUI_DEMO_MARKER("Popups/Context menus");
3784 if (ImGui::TreeNode("Context menus"))
3785 {
3786 HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
3787
3788 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
3789 // if (id == 0)
3790 // id = GetItemID(); // Use last item id
3791 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
3792 // OpenPopup(id);
3793 // return BeginPopup(id);
3794 // For advanced uses you may want to replicate and customize this code.
3795 // See more details in BeginPopupContextItem().
3796
3797 // Example 1
3798 // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
3799 // and BeginPopupContextItem() will use the last item ID as the popup ID.
3800 {
3801 const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
3802 static int selected = -1;
3803 for (int n = 0; n < 5; n++)
3804 {
3805 if (ImGui::Selectable(names[n], selected == n))
3806 selected = n;
3807 if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
3808 {
3809 selected = n;
3810 ImGui::Text("This a popup for \"%s\"!", names[n]);
3811 if (ImGui::Button("Close"))
3812 ImGui::CloseCurrentPopup();
3813 ImGui::EndPopup();
3814 }
3815 ImGui::SetItemTooltip("Right-click to open popup");
3816 }
3817 }
3818
3819 // Example 2
3820 // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
3821 // Using an explicit identifier is also convenient if you want to activate the popups from different locations.
3822 {
3823 HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
3824 static float value = 0.5f;
3825 ImGui::Text("Value = %.3f <-- (1) right-click this text", value);
3826 if (ImGui::BeginPopupContextItem("my popup"))
3827 {
3828 if (ImGui::Selectable("Set to zero")) value = 0.0f;
3829 if (ImGui::Selectable("Set to PI")) value = 3.1415f;
3830 ImGui::SetNextItemWidth(-FLT_MIN);
3831 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
3832 ImGui::EndPopup();
3833 }
3834
3835 // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
3836 // Here we make it that right-clicking this other text element opens the same popup as above.
3837 // The popup itself will be submitted by the code above.
3838 ImGui::Text("(2) Or right-click this text");
3839 ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
3840
3841 // Back to square one: manually open the same popup.
3842 if (ImGui::Button("(3) Or click this button"))
3843 ImGui::OpenPopup("my popup");
3844 }
3845
3846 // Example 3
3847 // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
3848 // we need to make sure your item identifier is stable.
3849 // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
3850 {
3851 HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
3852 static char name[32] = "Label1";
3853 char buf[64];
3854 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
3855 ImGui::Button(buf);
3856 if (ImGui::BeginPopupContextItem())
3857 {
3858 ImGui::Text("Edit name:");
3859 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
3860 if (ImGui::Button("Close"))
3861 ImGui::CloseCurrentPopup();
3862 ImGui::EndPopup();
3863 }
3864 ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
3865 }
3866
3867 ImGui::TreePop();
3868 }
3869
3870 IMGUI_DEMO_MARKER("Popups/Modals");
3871 if (ImGui::TreeNode("Modals"))
3872 {
3873 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
3874
3875 if (ImGui::Button("Delete.."))
3876 ImGui::OpenPopup("Delete?");
3877
3878 // Always center this window when appearing
3879 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
3880 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
3881
3882 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
3883 {
3884 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!");
3885 ImGui::Separator();
3886
3887 //static int unused_i = 0;
3888 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
3889
3890 static bool dont_ask_me_next_time = false;
3891 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3892 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
3893 ImGui::PopStyleVar();
3894
3895 if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3896 ImGui::SetItemDefaultFocus();
3897 ImGui::SameLine();
3898 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3899 ImGui::EndPopup();
3900 }
3901
3902 if (ImGui::Button("Stacked modals.."))
3903 ImGui::OpenPopup("Stacked 1");
3904 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
3905 {
3906 if (ImGui::BeginMenuBar())
3907 {
3908 if (ImGui::BeginMenu("File"))
3909 {
3910 if (ImGui::MenuItem("Some menu item")) {}
3911 ImGui::EndMenu();
3912 }
3913 ImGui::EndMenuBar();
3914 }
3915 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
3916
3917 // Testing behavior of widgets stacking their own regular popups over the modal.
3918 static int item = 1;
3919 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
3920 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
3921 ImGui::ColorEdit4("color", color);
3922
3923 if (ImGui::Button("Add another modal.."))
3924 ImGui::OpenPopup("Stacked 2");
3925
3926 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
3927 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
3928 // of the bool actually doesn't matter here.
3929 bool unused_open = true;
3930 if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
3931 {
3932 ImGui::Text("Hello from Stacked The Second!");
3933 if (ImGui::Button("Close"))
3934 ImGui::CloseCurrentPopup();
3935 ImGui::EndPopup();
3936 }
3937
3938 if (ImGui::Button("Close"))
3939 ImGui::CloseCurrentPopup();
3940 ImGui::EndPopup();
3941 }
3942
3943 ImGui::TreePop();
3944 }
3945
3946 IMGUI_DEMO_MARKER("Popups/Menus inside a regular window");
3947 if (ImGui::TreeNode("Menus inside a regular window"))
3948 {
3949 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
3950 ImGui::Separator();
3951
3952 ImGui::MenuItem("Menu item", "CTRL+M");
3953 if (ImGui::BeginMenu("Menu inside a regular window"))
3954 {
3955 ShowExampleMenuFile();
3956 ImGui::EndMenu();
3957 }
3958 ImGui::Separator();
3959 ImGui::TreePop();
3960 }
3961}
3962
3963// Dummy data structure that we use for the Table demo.
3964// (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure is defined inside the demo function)
3965namespace
3966{
3967// We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
3968// This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
3969// But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
3970// If you don't use sorting, you will generally never care about giving column an ID!
3971enum MyItemColumnID
3972{
3973 MyItemColumnID_ID,
3974 MyItemColumnID_Name,
3975 MyItemColumnID_Action,
3976 MyItemColumnID_Quantity,
3977 MyItemColumnID_Description
3978};
3979
3980struct MyItem
3981{
3982 int ID;
3983 const char* Name;
3984 int Quantity;
3985
3986 // We have a problem which is affecting _only this demo_ and should not affect your code:
3987 // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
3988 // however qsort doesn't allow passing user data to comparing function.
3989 // As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
3990 // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
3991 // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
3992 // very often by the sorting algorithm it would be a little wasteful.
3993 static const ImGuiTableSortSpecs* s_current_sort_specs;
3994
3995 static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
3996 {
3997 s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
3998 if (items_count > 1)
3999 qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
4000 s_current_sort_specs = NULL;
4001 }
4002
4003 // Compare function to be used by qsort()
4004 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
4005 {
4006 const MyItem* a = (const MyItem*)lhs;
4007 const MyItem* b = (const MyItem*)rhs;
4008 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
4009 {
4010 // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
4011 // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
4012 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
4013 int delta = 0;
4014 switch (sort_spec->ColumnUserID)
4015 {
4016 case MyItemColumnID_ID: delta = (a->ID - b->ID); break;
4017 case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break;
4018 case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break;
4019 case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break;
4020 default: IM_ASSERT(0); break;
4021 }
4022 if (delta > 0)
4023 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
4024 if (delta < 0)
4025 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
4026 }
4027
4028 // qsort() is instable so always return a way to differenciate items.
4029 // Your own compare function may want to avoid fallback on implicit sort specs.
4030 // e.g. a Name compare if it wasn't already part of the sort specs.
4031 return (a->ID - b->ID);
4032 }
4033};
4034const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
4035}
4036
4037// Make the UI compact because there are so many fields
4038static void PushStyleCompact()
4039{
4040 ImGuiStyle& style = ImGui::GetStyle();
4041 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f)));
4042 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f)));
4043}
4044
4045static void PopStyleCompact()
4046{
4047 ImGui::PopStyleVar(2);
4048}
4049
4050// Show a combo box with a choice of sizing policies
4051static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
4052{
4053 struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
4054 static const EnumDesc policies[] =
4055 {
4056 { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." },
4057 { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
4058 { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
4059 { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
4060 { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
4061 };
4062 int idx;
4063 for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
4064 if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
4065 break;
4066 const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
4067 if (ImGui::BeginCombo("Sizing Policy", preview_text))
4068 {
4069 for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
4070 if (ImGui::Selectable(policies[n].Name, idx == n))
4071 *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
4072 ImGui::EndCombo();
4073 }
4074 ImGui::SameLine();
4075 ImGui::TextDisabled("(?)");
4076 if (ImGui::BeginItemTooltip())
4077 {
4078 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
4079 for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
4080 {
4081 ImGui::Separator();
4082 ImGui::Text("%s:", policies[m].Name);
4083 ImGui::Separator();
4084 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
4085 ImGui::TextUnformatted(policies[m].Tooltip);
4086 }
4087 ImGui::PopTextWrapPos();
4088 ImGui::EndTooltip();
4089 }
4090}
4091
4092static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
4093{
4094 ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
4095 ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
4096 ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
4097 if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
4098 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
4099 if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
4100 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
4101 ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
4102 ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
4103 ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
4104 ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
4105 ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
4106 ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
4107 ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
4108 ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
4109 ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
4110 ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
4111 ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
4112 ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
4113 ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
4114 ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
4115}
4116
4117static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
4118{
4119 ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
4120 ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
4121 ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
4122 ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
4123}
4124
4125static void ShowDemoWindowTables()
4126{
4127 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
4128 IMGUI_DEMO_MARKER("Tables");
4129 if (!ImGui::CollapsingHeader("Tables & Columns"))
4130 return;
4131
4132 // Using those as a base value to create width/height that are factor of the size of our font
4133 const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
4134 const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
4135
4136 ImGui::PushID("Tables");
4137
4138 int open_action = -1;
4139 if (ImGui::Button("Expand all"))
4140 open_action = 1;
4141 ImGui::SameLine();
4142 if (ImGui::Button("Collapse all"))
4143 open_action = 0;
4144 ImGui::SameLine();
4145
4146 // Options
4147 static bool disable_indent = false;
4148 ImGui::Checkbox("Disable tree indentation", &disable_indent);
4149 ImGui::SameLine();
4150 HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
4151 ImGui::Separator();
4152 if (disable_indent)
4153 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
4154
4155 // About Styling of tables
4156 // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
4157 // There are however a few settings that a shared and part of the ImGuiStyle structure:
4158 // style.CellPadding // Padding within each cell
4159 // style.Colors[ImGuiCol_TableHeaderBg] // Table header background
4160 // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders
4161 // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders
4162 // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
4163 // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
4164
4165 // Demos
4166 if (open_action != -1)
4167 ImGui::SetNextItemOpen(open_action != 0);
4168 IMGUI_DEMO_MARKER("Tables/Basic");
4169 if (ImGui::TreeNode("Basic"))
4170 {
4171 // Here we will showcase three different ways to output a table.
4172 // They are very simple variations of a same thing!
4173
4174 // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
4175 // In many situations, this is the most flexible and easy to use pattern.
4176 HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
4177 if (ImGui::BeginTable("table1", 3))
4178 {
4179 for (int row = 0; row < 4; row++)
4180 {
4181 ImGui::TableNextRow();
4182 for (int column = 0; column < 3; column++)
4183 {
4184 ImGui::TableSetColumnIndex(column);
4185 ImGui::Text("Row %d Column %d", row, column);
4186 }
4187 }
4188 ImGui::EndTable();
4189 }
4190
4191 // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
4192 // This is generally more convenient when you have code manually submitting the contents of each column.
4193 HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
4194 if (ImGui::BeginTable("table2", 3))
4195 {
4196 for (int row = 0; row < 4; row++)
4197 {
4198 ImGui::TableNextRow();
4199 ImGui::TableNextColumn();
4200 ImGui::Text("Row %d", row);
4201 ImGui::TableNextColumn();
4202 ImGui::Text("Some contents");
4203 ImGui::TableNextColumn();
4204 ImGui::Text("123.456");
4205 }
4206 ImGui::EndTable();
4207 }
4208
4209 // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
4210 // as TableNextColumn() will automatically wrap around and create new rows as needed.
4211 // This is generally more convenient when your cells all contains the same type of data.
4212 HelpMarker(
4213 "Only using TableNextColumn(), which tends to be convenient for tables where every cell contains "
4214 "the same type of contents.\n This is also more similar to the old NextColumn() function of the "
4215 "Columns API, and provided to facilitate the Columns->Tables API transition.");
4216 if (ImGui::BeginTable("table3", 3))
4217 {
4218 for (int item = 0; item < 14; item++)
4219 {
4220 ImGui::TableNextColumn();
4221 ImGui::Text("Item %d", item);
4222 }
4223 ImGui::EndTable();
4224 }
4225
4226 ImGui::TreePop();
4227 }
4228
4229 if (open_action != -1)
4230 ImGui::SetNextItemOpen(open_action != 0);
4231 IMGUI_DEMO_MARKER("Tables/Borders, background");
4232 if (ImGui::TreeNode("Borders, background"))
4233 {
4234 // Expose a few Borders related flags interactively
4235 enum ContentsType { CT_Text, CT_FillButton };
4236 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
4237 static bool display_headers = false;
4238 static int contents_type = CT_Text;
4239
4240 PushStyleCompact();
4241 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
4242 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
4243 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterH");
4244 ImGui::Indent();
4245
4246 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
4247 ImGui::Indent();
4248 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
4249 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
4250 ImGui::Unindent();
4251
4252 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
4253 ImGui::Indent();
4254 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
4255 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
4256 ImGui::Unindent();
4257
4258 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
4259 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
4260 ImGui::Unindent();
4261
4262 ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
4263 ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
4264 ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
4265 ImGui::Checkbox("Display headers", &display_headers);
4266 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
4267 PopStyleCompact();
4268
4269 if (ImGui::BeginTable("table1", 3, flags))
4270 {
4271 // Display headers so we can inspect their interaction with borders
4272 // (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)
4273 if (display_headers)
4274 {
4275 ImGui::TableSetupColumn("One");
4276 ImGui::TableSetupColumn("Two");
4277 ImGui::TableSetupColumn("Three");
4278 ImGui::TableHeadersRow();
4279 }
4280
4281 for (int row = 0; row < 5; row++)
4282 {
4283 ImGui::TableNextRow();
4284 for (int column = 0; column < 3; column++)
4285 {
4286 ImGui::TableSetColumnIndex(column);
4287 char buf[32];
4288 sprintf(buf, "Hello %d,%d", column, row);
4289 if (contents_type == CT_Text)
4291 else if (contents_type == CT_FillButton)
4292 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4293 }
4294 }
4295 ImGui::EndTable();
4296 }
4297 ImGui::TreePop();
4298 }
4299
4300 if (open_action != -1)
4301 ImGui::SetNextItemOpen(open_action != 0);
4302 IMGUI_DEMO_MARKER("Tables/Resizable, stretch");
4303 if (ImGui::TreeNode("Resizable, stretch"))
4304 {
4305 // By default, if we don't enable ScrollX the sizing policy for each column is "Stretch"
4306 // All columns maintain a sizing weight, and they will occupy all available width.
4307 static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
4308 PushStyleCompact();
4309 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
4310 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
4311 ImGui::SameLine(); HelpMarker(
4312 "Using the _Resizable flag automatically enables the _BordersInnerV flag as well, "
4313 "this is why the resize borders are still showing when unchecking this.");
4314 PopStyleCompact();
4315
4316 if (ImGui::BeginTable("table1", 3, flags))
4317 {
4318 for (int row = 0; row < 5; row++)
4319 {
4320 ImGui::TableNextRow();
4321 for (int column = 0; column < 3; column++)
4322 {
4323 ImGui::TableSetColumnIndex(column);
4324 ImGui::Text("Hello %d,%d", column, row);
4325 }
4326 }
4327 ImGui::EndTable();
4328 }
4329 ImGui::TreePop();
4330 }
4331
4332 if (open_action != -1)
4333 ImGui::SetNextItemOpen(open_action != 0);
4334 IMGUI_DEMO_MARKER("Tables/Resizable, fixed");
4335 if (ImGui::TreeNode("Resizable, fixed"))
4336 {
4337 // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
4338 // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
4339 // If there is not enough available width to fit all columns, they will however be resized down.
4340 // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
4341 HelpMarker(
4342 "Using _Resizable + _SizingFixedFit flags.\n"
4343 "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
4344 "Double-click a column border to auto-fit the column to its contents.");
4345 PushStyleCompact();
4346 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
4347 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
4348 PopStyleCompact();
4349
4350 if (ImGui::BeginTable("table1", 3, flags))
4351 {
4352 for (int row = 0; row < 5; row++)
4353 {
4354 ImGui::TableNextRow();
4355 for (int column = 0; column < 3; column++)
4356 {
4357 ImGui::TableSetColumnIndex(column);
4358 ImGui::Text("Hello %d,%d", column, row);
4359 }
4360 }
4361 ImGui::EndTable();
4362 }
4363 ImGui::TreePop();
4364 }
4365
4366 if (open_action != -1)
4367 ImGui::SetNextItemOpen(open_action != 0);
4368 IMGUI_DEMO_MARKER("Tables/Resizable, mixed");
4369 if (ImGui::TreeNode("Resizable, mixed"))
4370 {
4371 HelpMarker(
4372 "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
4373 "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
4374 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4375
4376 if (ImGui::BeginTable("table1", 3, flags))
4377 {
4378 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
4379 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
4380 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
4381 ImGui::TableHeadersRow();
4382 for (int row = 0; row < 5; row++)
4383 {
4384 ImGui::TableNextRow();
4385 for (int column = 0; column < 3; column++)
4386 {
4387 ImGui::TableSetColumnIndex(column);
4388 ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
4389 }
4390 }
4391 ImGui::EndTable();
4392 }
4393 if (ImGui::BeginTable("table2", 6, flags))
4394 {
4395 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
4396 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
4397 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
4398 ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
4399 ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
4400 ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
4401 ImGui::TableHeadersRow();
4402 for (int row = 0; row < 5; row++)
4403 {
4404 ImGui::TableNextRow();
4405 for (int column = 0; column < 6; column++)
4406 {
4407 ImGui::TableSetColumnIndex(column);
4408 ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
4409 }
4410 }
4411 ImGui::EndTable();
4412 }
4413 ImGui::TreePop();
4414 }
4415
4416 if (open_action != -1)
4417 ImGui::SetNextItemOpen(open_action != 0);
4418 IMGUI_DEMO_MARKER("Tables/Reorderable, hideable, with headers");
4419 if (ImGui::TreeNode("Reorderable, hideable, with headers"))
4420 {
4421 HelpMarker(
4422 "Click and drag column headers to reorder columns.\n\n"
4423 "Right-click on a header to open a context menu.");
4424 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
4425 PushStyleCompact();
4426 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
4427 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
4428 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
4429 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
4430 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
4431 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
4432 PopStyleCompact();
4433
4434 if (ImGui::BeginTable("table1", 3, flags))
4435 {
4436 // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
4437 // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
4438 ImGui::TableSetupColumn("One");
4439 ImGui::TableSetupColumn("Two");
4440 ImGui::TableSetupColumn("Three");
4441 ImGui::TableHeadersRow();
4442 for (int row = 0; row < 6; row++)
4443 {
4444 ImGui::TableNextRow();
4445 for (int column = 0; column < 3; column++)
4446 {
4447 ImGui::TableSetColumnIndex(column);
4448 ImGui::Text("Hello %d,%d", column, row);
4449 }
4450 }
4451 ImGui::EndTable();
4452 }
4453
4454 // Use outer_size.x == 0.0f instead of default to make the table as tight as possible
4455 // (only valid when no scrolling and no stretch column)
4456 if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
4457 {
4458 ImGui::TableSetupColumn("One");
4459 ImGui::TableSetupColumn("Two");
4460 ImGui::TableSetupColumn("Three");
4461 ImGui::TableHeadersRow();
4462 for (int row = 0; row < 6; row++)
4463 {
4464 ImGui::TableNextRow();
4465 for (int column = 0; column < 3; column++)
4466 {
4467 ImGui::TableSetColumnIndex(column);
4468 ImGui::Text("Fixed %d,%d", column, row);
4469 }
4470 }
4471 ImGui::EndTable();
4472 }
4473 ImGui::TreePop();
4474 }
4475
4476 if (open_action != -1)
4477 ImGui::SetNextItemOpen(open_action != 0);
4478 IMGUI_DEMO_MARKER("Tables/Padding");
4479 if (ImGui::TreeNode("Padding"))
4480 {
4481 // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
4482 // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
4483 HelpMarker(
4484 "We often want outer padding activated when any using features which makes the edges of a column visible:\n"
4485 "e.g.:\n"
4486 "- BorderOuterV\n"
4487 "- any form of row selection\n"
4488 "Because of this, activating BorderOuterV sets the default to PadOuterX. "
4489 "Using PadOuterX or NoPadOuterX you can override the default.\n\n"
4490 "Actual padding values are using style.CellPadding.\n\n"
4491 "In this demo we don't show horizontal borders to emphasize how they don't affect default horizontal padding.");
4492
4493 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
4494 PushStyleCompact();
4495 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
4496 ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
4497 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
4498 ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
4499 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
4500 ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
4501 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
4502 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
4503 static bool show_headers = false;
4504 ImGui::Checkbox("show_headers", &show_headers);
4505 PopStyleCompact();
4506
4507 if (ImGui::BeginTable("table_padding", 3, flags1))
4508 {
4509 if (show_headers)
4510 {
4511 ImGui::TableSetupColumn("One");
4512 ImGui::TableSetupColumn("Two");
4513 ImGui::TableSetupColumn("Three");
4514 ImGui::TableHeadersRow();
4515 }
4516
4517 for (int row = 0; row < 5; row++)
4518 {
4519 ImGui::TableNextRow();
4520 for (int column = 0; column < 3; column++)
4521 {
4522 ImGui::TableSetColumnIndex(column);
4523 if (row == 0)
4524 {
4525 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
4526 }
4527 else
4528 {
4529 char buf[32];
4530 sprintf(buf, "Hello %d,%d", column, row);
4531 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
4532 }
4533 //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
4534 // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
4535 }
4536 }
4537 ImGui::EndTable();
4538 }
4539
4540 // Second example: set style.CellPadding to (0.0) or a custom value.
4541 // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
4542 HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
4543 static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
4544 static ImVec2 cell_padding(0.0f, 0.0f);
4545 static bool show_widget_frame_bg = true;
4546
4547 PushStyleCompact();
4548 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
4549 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
4550 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
4551 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
4552 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
4553 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
4554 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
4555 ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
4556 ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
4557 PopStyleCompact();
4558
4559 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
4560 if (ImGui::BeginTable("table_padding_2", 3, flags2))
4561 {
4562 static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
4563 static bool init = true;
4564 if (!show_widget_frame_bg)
4565 ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
4566 for (int cell = 0; cell < 3 * 5; cell++)
4567 {
4568 ImGui::TableNextColumn();
4569 if (init)
4570 strcpy(text_bufs[cell], "edit me");
4571 ImGui::SetNextItemWidth(-FLT_MIN);
4572 ImGui::PushID(cell);
4573 ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
4574 ImGui::PopID();
4575 }
4576 if (!show_widget_frame_bg)
4577 ImGui::PopStyleColor();
4578 init = false;
4579 ImGui::EndTable();
4580 }
4581 ImGui::PopStyleVar();
4582
4583 ImGui::TreePop();
4584 }
4585
4586 if (open_action != -1)
4587 ImGui::SetNextItemOpen(open_action != 0);
4588 IMGUI_DEMO_MARKER("Tables/Explicit widths");
4589 if (ImGui::TreeNode("Sizing policies"))
4590 {
4591 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
4592 PushStyleCompact();
4593 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
4594 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
4595 PopStyleCompact();
4596
4597 static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
4598 for (int table_n = 0; table_n < 4; table_n++)
4599 {
4600 ImGui::PushID(table_n);
4601 ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
4602 EditTableSizingFlags(&sizing_policy_flags[table_n]);
4603
4604 // To make it easier to understand the different sizing policy,
4605 // For each policy: we display one table where the columns have equal contents width,
4606 // and one where the columns have different contents width.
4607 if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
4608 {
4609 for (int row = 0; row < 3; row++)
4610 {
4611 ImGui::TableNextRow();
4612 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
4613 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
4614 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
4615 }
4616 ImGui::EndTable();
4617 }
4618 if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
4619 {
4620 for (int row = 0; row < 3; row++)
4621 {
4622 ImGui::TableNextRow();
4623 ImGui::TableNextColumn(); ImGui::Text("AAAA");
4624 ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
4625 ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
4626 }
4627 ImGui::EndTable();
4628 }
4629 ImGui::PopID();
4630 }
4631
4632 ImGui::Spacing();
4633 ImGui::TextUnformatted("Advanced");
4634 ImGui::SameLine();
4635 HelpMarker(
4636 "This section allows you to interact and see the effect of various sizing policies "
4637 "depending on whether Scroll is enabled and the contents of your columns.");
4638
4639 enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
4640 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
4641 static int contents_type = CT_ShowWidth;
4642 static int column_count = 3;
4643
4644 PushStyleCompact();
4645 ImGui::PushID("Advanced");
4646 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
4647 EditTableSizingFlags(&flags);
4648 ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
4649 if (contents_type == CT_FillButton)
4650 {
4651 ImGui::SameLine();
4652 HelpMarker(
4653 "Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop "
4654 "where contents width can feed into auto-column width can feed into contents width.");
4655 }
4656 ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
4657 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
4658 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
4659 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
4660 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
4661 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
4662 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
4663 ImGui::PopItemWidth();
4664 ImGui::PopID();
4665 PopStyleCompact();
4666
4667 if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
4668 {
4669 for (int cell = 0; cell < 10 * column_count; cell++)
4670 {
4671 ImGui::TableNextColumn();
4672 int column = ImGui::TableGetColumnIndex();
4673 int row = ImGui::TableGetRowIndex();
4674
4675 ImGui::PushID(cell);
4676 char label[32];
4677 static char text_buf[32] = "";
4678 sprintf(label, "Hello %d,%d", column, row);
4679 switch (contents_type)
4680 {
4681 case CT_ShortText: ImGui::TextUnformatted(label); break;
4682 case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
4683 case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
4684 case CT_Button: ImGui::Button(label); break;
4685 case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
4686 case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
4687 }
4688 ImGui::PopID();
4689 }
4690 ImGui::EndTable();
4691 }
4692 ImGui::TreePop();
4693 }
4694
4695 if (open_action != -1)
4696 ImGui::SetNextItemOpen(open_action != 0);
4697 IMGUI_DEMO_MARKER("Tables/Vertical scrolling, with clipping");
4698 if (ImGui::TreeNode("Vertical scrolling, with clipping"))
4699 {
4700 HelpMarker(
4701 "Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\n"
4702 "We also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
4703 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4704
4705 PushStyleCompact();
4706 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
4707 PopStyleCompact();
4708
4709 // When using ScrollX or ScrollY we need to specify a size for our table container!
4710 // Otherwise by default the table will fit all available space, like a BeginChild() call.
4711 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
4712 if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
4713 {
4714 ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
4715 ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
4716 ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
4717 ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
4718 ImGui::TableHeadersRow();
4719
4720 // Demonstrate using clipper for large vertical lists
4721 ImGuiListClipper clipper;
4722 clipper.Begin(1000);
4723 while (clipper.Step())
4724 {
4725 for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
4726 {
4727 ImGui::TableNextRow();
4728 for (int column = 0; column < 3; column++)
4729 {
4730 ImGui::TableSetColumnIndex(column);
4731 ImGui::Text("Hello %d,%d", column, row);
4732 }
4733 }
4734 }
4735 ImGui::EndTable();
4736 }
4737 ImGui::TreePop();
4738 }
4739
4740 if (open_action != -1)
4741 ImGui::SetNextItemOpen(open_action != 0);
4742 IMGUI_DEMO_MARKER("Tables/Horizontal scrolling");
4743 if (ImGui::TreeNode("Horizontal scrolling"))
4744 {
4745 HelpMarker(
4746 "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
4747 "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
4748 "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX, "
4749 "because the container window won't automatically extend vertically to fix contents "
4750 "(this may be improved in future versions).");
4751 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4752 static int freeze_cols = 1;
4753 static int freeze_rows = 1;
4754
4755 PushStyleCompact();
4756 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
4757 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
4758 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
4759 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
4760 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
4761 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
4762 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
4763 PopStyleCompact();
4764
4765 // When using ScrollX or ScrollY we need to specify a size for our table container!
4766 // Otherwise by default the table will fit all available space, like a BeginChild() call.
4767 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
4768 if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
4769 {
4770 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
4771 ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
4772 ImGui::TableSetupColumn("One");
4773 ImGui::TableSetupColumn("Two");
4774 ImGui::TableSetupColumn("Three");
4775 ImGui::TableSetupColumn("Four");
4776 ImGui::TableSetupColumn("Five");
4777 ImGui::TableSetupColumn("Six");
4778 ImGui::TableHeadersRow();
4779 for (int row = 0; row < 20; row++)
4780 {
4781 ImGui::TableNextRow();
4782 for (int column = 0; column < 7; column++)
4783 {
4784 // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
4785 // Because here we know that:
4786 // - A) all our columns are contributing the same to row height
4787 // - B) column 0 is always visible,
4788 // We only always submit this one column and can skip others.
4789 // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
4790 if (!ImGui::TableSetColumnIndex(column) && column > 0)
4791 continue;
4792 if (column == 0)
4793 ImGui::Text("Line %d", row);
4794 else
4795 ImGui::Text("Hello world %d,%d", column, row);
4796 }
4797 }
4798 ImGui::EndTable();
4799 }
4800
4801 ImGui::Spacing();
4802 ImGui::TextUnformatted("Stretch + ScrollX");
4803 ImGui::SameLine();
4804 HelpMarker(
4805 "Showcase using Stretch columns + ScrollX together: "
4806 "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
4807 "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns "
4808 "along with ScrollX doesn't make sense.");
4809 static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
4810 static float inner_width = 1000.0f;
4811 PushStyleCompact();
4812 ImGui::PushID("flags3");
4813 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
4814 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
4815 ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
4816 ImGui::PopItemWidth();
4817 ImGui::PopID();
4818 PopStyleCompact();
4819 if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
4820 {
4821 for (int cell = 0; cell < 20 * 7; cell++)
4822 {
4823 ImGui::TableNextColumn();
4824 ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
4825 }
4826 ImGui::EndTable();
4827 }
4828 ImGui::TreePop();
4829 }
4830
4831 if (open_action != -1)
4832 ImGui::SetNextItemOpen(open_action != 0);
4833 IMGUI_DEMO_MARKER("Tables/Columns flags");
4834 if (ImGui::TreeNode("Columns flags"))
4835 {
4836 // Create a first table just to show all the options/flags we want to make visible in our example!
4837 const int column_count = 3;
4838 const char* column_names[column_count] = { "One", "Two", "Three" };
4839 static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
4840 static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
4841
4842 if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
4843 {
4844 PushStyleCompact();
4845 for (int column = 0; column < column_count; column++)
4846 {
4847 ImGui::TableNextColumn();
4848 ImGui::PushID(column);
4849 ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation across columns
4850 ImGui::Text("'%s'", column_names[column]);
4851 ImGui::Spacing();
4852 ImGui::Text("Input flags:");
4853 EditTableColumnsFlags(&column_flags[column]);
4854 ImGui::Spacing();
4855 ImGui::Text("Output flags:");
4856 ImGui::BeginDisabled();
4857 ShowTableColumnsStatusFlags(column_flags_out[column]);
4858 ImGui::EndDisabled();
4859 ImGui::PopID();
4860 }
4861 PopStyleCompact();
4862 ImGui::EndTable();
4863 }
4864
4865 // Create the real table we care about for the example!
4866 // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above,
4867 // otherwise in a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible
4868 // + resizing the parent window down).
4869 const ImGuiTableFlags flags
4870 = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
4871 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
4872 | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
4873 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
4874 if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
4875 {
4876 bool has_angled_header = false;
4877 for (int column = 0; column < column_count; column++)
4878 {
4879 has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
4880 ImGui::TableSetupColumn(column_names[column], column_flags[column]);
4881 }
4882 if (has_angled_header)
4883 ImGui::TableAngledHeadersRow();
4884 ImGui::TableHeadersRow();
4885 for (int column = 0; column < column_count; column++)
4886 column_flags_out[column] = ImGui::TableGetColumnFlags(column);
4887 float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
4888 for (int row = 0; row < 8; row++)
4889 {
4890 // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
4891 ImGui::Indent(indent_step);
4892 ImGui::TableNextRow();
4893 for (int column = 0; column < column_count; column++)
4894 {
4895 ImGui::TableSetColumnIndex(column);
4896 ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
4897 }
4898 }
4899 ImGui::Unindent(indent_step * 8.0f);
4900
4901 ImGui::EndTable();
4902 }
4903 ImGui::TreePop();
4904 }
4905
4906 if (open_action != -1)
4907 ImGui::SetNextItemOpen(open_action != 0);
4908 IMGUI_DEMO_MARKER("Tables/Columns widths");
4909 if (ImGui::TreeNode("Columns widths"))
4910 {
4911 HelpMarker("Using TableSetupColumn() to setup default width.");
4912
4913 static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
4914 PushStyleCompact();
4915 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
4916 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
4917 PopStyleCompact();
4918 if (ImGui::BeginTable("table1", 3, flags1))
4919 {
4920 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
4921 ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
4922 ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
4923 ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto
4924 ImGui::TableHeadersRow();
4925 for (int row = 0; row < 4; row++)
4926 {
4927 ImGui::TableNextRow();
4928 for (int column = 0; column < 3; column++)
4929 {
4930 ImGui::TableSetColumnIndex(column);
4931 if (row == 0)
4932 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
4933 else
4934 ImGui::Text("Hello %d,%d", column, row);
4935 }
4936 }
4937 ImGui::EndTable();
4938 }
4939
4940 HelpMarker(
4941 "Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, "
4942 "fixed columns with set width may still be shrunk down if there's not enough space in the host.");
4943
4944 static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
4945 PushStyleCompact();
4946 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
4947 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
4948 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
4949 PopStyleCompact();
4950 if (ImGui::BeginTable("table2", 4, flags2))
4951 {
4952 // We could also set ImGuiTableFlags_SizingFixedFit on the table and then all columns
4953 // will default to ImGuiTableColumnFlags_WidthFixed.
4954 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
4955 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
4956 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
4957 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
4958 for (int row = 0; row < 5; row++)
4959 {
4960 ImGui::TableNextRow();
4961 for (int column = 0; column < 4; column++)
4962 {
4963 ImGui::TableSetColumnIndex(column);
4964 if (row == 0)
4965 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
4966 else
4967 ImGui::Text("Hello %d,%d", column, row);
4968 }
4969 }
4970 ImGui::EndTable();
4971 }
4972 ImGui::TreePop();
4973 }
4974
4975 if (open_action != -1)
4976 ImGui::SetNextItemOpen(open_action != 0);
4977 IMGUI_DEMO_MARKER("Tables/Nested tables");
4978 if (ImGui::TreeNode("Nested tables"))
4979 {
4980 HelpMarker("This demonstrates embedding a table into another table cell.");
4981
4982 if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
4983 {
4984 ImGui::TableSetupColumn("A0");
4985 ImGui::TableSetupColumn("A1");
4986 ImGui::TableHeadersRow();
4987
4988 ImGui::TableNextColumn();
4989 ImGui::Text("A0 Row 0");
4990 {
4991 float rows_height = TEXT_BASE_HEIGHT * 2;
4992 if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
4993 {
4994 ImGui::TableSetupColumn("B0");
4995 ImGui::TableSetupColumn("B1");
4996 ImGui::TableHeadersRow();
4997
4998 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
4999 ImGui::TableNextColumn();
5000 ImGui::Text("B0 Row 0");
5001 ImGui::TableNextColumn();
5002 ImGui::Text("B1 Row 0");
5003 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
5004 ImGui::TableNextColumn();
5005 ImGui::Text("B0 Row 1");
5006 ImGui::TableNextColumn();
5007 ImGui::Text("B1 Row 1");
5008
5009 ImGui::EndTable();
5010 }
5011 }
5012 ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
5013 ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
5014 ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
5015 ImGui::EndTable();
5016 }
5017 ImGui::TreePop();
5018 }
5019
5020 if (open_action != -1)
5021 ImGui::SetNextItemOpen(open_action != 0);
5022 IMGUI_DEMO_MARKER("Tables/Row height");
5023 if (ImGui::TreeNode("Row height"))
5024 {
5025 HelpMarker(
5026 "You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, "
5027 "so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\n"
5028 "We cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
5029 if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
5030 {
5031 for (int row = 0; row < 8; row++)
5032 {
5033 float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
5034 ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
5035 ImGui::TableNextColumn();
5036 ImGui::Text("min_row_height = %.2f", min_row_height);
5037 }
5038 ImGui::EndTable();
5039 }
5040
5041 HelpMarker(
5042 "Showcase using SameLine(0,0) to share Current Line Height between cells.\n\n"
5043 "Please note that Tables Row Height is not the same thing as Current Line Height, "
5044 "as a table cell may contains multiple lines.");
5045 if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
5046 {
5047 ImGui::TableNextRow();
5048 ImGui::TableNextColumn();
5049 ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
5050 ImGui::TableNextColumn();
5051 ImGui::Text("Line 1");
5052 ImGui::Text("Line 2");
5053
5054 ImGui::TableNextRow();
5055 ImGui::TableNextColumn();
5056 ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
5057 ImGui::TableNextColumn();
5058 ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
5059 ImGui::Text("Line 1, with SameLine(0,0)");
5060 ImGui::Text("Line 2");
5061
5062 ImGui::EndTable();
5063 }
5064
5065 HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
5066 if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
5067 {
5068 ImGuiStyle& style = ImGui::GetStyle();
5069 for (int row = 0; row < 8; row++)
5070 {
5071 if ((row % 3) == 2)
5072 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(style.CellPadding.x, 20.0f));
5073 ImGui::TableNextRow(ImGuiTableRowFlags_None);
5074 ImGui::TableNextColumn();
5075 ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
5076 if ((row % 3) == 2)
5077 ImGui::PopStyleVar();
5078 }
5079 ImGui::EndTable();
5080 }
5081
5082 ImGui::TreePop();
5083 }
5084
5085 if (open_action != -1)
5086 ImGui::SetNextItemOpen(open_action != 0);
5087 IMGUI_DEMO_MARKER("Tables/Outer size");
5088 if (ImGui::TreeNode("Outer size"))
5089 {
5090 // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
5091 // Important to that note how the two flags have slightly different behaviors!
5092 ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
5093 PushStyleCompact();
5094 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
5095 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5096 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
5097 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
5098 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
5099 PopStyleCompact();
5100
5101 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
5102 if (ImGui::BeginTable("table1", 3, flags, outer_size))
5103 {
5104 for (int row = 0; row < 10; row++)
5105 {
5106 ImGui::TableNextRow();
5107 for (int column = 0; column < 3; column++)
5108 {
5109 ImGui::TableNextColumn();
5110 ImGui::Text("Cell %d,%d", column, row);
5111 }
5112 }
5113 ImGui::EndTable();
5114 }
5115 ImGui::SameLine();
5116 ImGui::Text("Hello!");
5117
5118 ImGui::Spacing();
5119
5120 ImGui::Text("Using explicit size:");
5121 if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
5122 {
5123 for (int row = 0; row < 5; row++)
5124 {
5125 ImGui::TableNextRow();
5126 for (int column = 0; column < 3; column++)
5127 {
5128 ImGui::TableNextColumn();
5129 ImGui::Text("Cell %d,%d", column, row);
5130 }
5131 }
5132 ImGui::EndTable();
5133 }
5134 ImGui::SameLine();
5135 if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
5136 {
5137 for (int row = 0; row < 3; row++)
5138 {
5139 ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f);
5140 for (int column = 0; column < 3; column++)
5141 {
5142 ImGui::TableNextColumn();
5143 ImGui::Text("Cell %d,%d", column, row);
5144 }
5145 }
5146 ImGui::EndTable();
5147 }
5148
5149 ImGui::TreePop();
5150 }
5151
5152 if (open_action != -1)
5153 ImGui::SetNextItemOpen(open_action != 0);
5154 IMGUI_DEMO_MARKER("Tables/Background color");
5155 if (ImGui::TreeNode("Background color"))
5156 {
5157 static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
5158 static int row_bg_type = 1;
5159 static int row_bg_target = 1;
5160 static int cell_bg_type = 1;
5161
5162 PushStyleCompact();
5163 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
5164 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5165 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
5166 ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
5167 ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.");
5168 ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
5169 IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
5170 IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
5171 IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
5172 PopStyleCompact();
5173
5174 if (ImGui::BeginTable("table1", 5, flags))
5175 {
5176 for (int row = 0; row < 6; row++)
5177 {
5178 ImGui::TableNextRow();
5179
5180 // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
5181 // 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.
5182 if (row_bg_type != 0)
5183 {
5184 ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient?
5185 ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
5186 }
5187
5188 // Fill cells
5189 for (int column = 0; column < 5; column++)
5190 {
5191 ImGui::TableSetColumnIndex(column);
5192 ImGui::Text("%c%c", 'A' + row, '0' + column);
5193
5194 // Change background of Cells B1->C2
5195 // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
5196 // (the CellBg color will be blended over the RowBg and ColumnBg colors)
5197 // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
5198 if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
5199 {
5200 ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
5201 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
5202 }
5203 }
5204 }
5205 ImGui::EndTable();
5206 }
5207 ImGui::TreePop();
5208 }
5209
5210 if (open_action != -1)
5211 ImGui::SetNextItemOpen(open_action != 0);
5212 IMGUI_DEMO_MARKER("Tables/Tree view");
5213 if (ImGui::TreeNode("Tree view"))
5214 {
5215 static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
5216
5217 static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns;
5218 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth);
5219 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns);
5220
5221 HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns.");
5222 if (ImGui::BeginTable("3ways", 3, flags))
5223 {
5224 // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
5225 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
5226 ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
5227 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
5228 ImGui::TableHeadersRow();
5229
5230 // Simple storage to output a dummy file-system.
5231 struct MyTreeNode
5232 {
5233 const char* Name;
5234 const char* Type;
5235 int Size;
5236 int ChildIdx;
5237 int ChildCount;
5238 static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
5239 {
5240 ImGui::TableNextRow();
5241 ImGui::TableNextColumn();
5242 const bool is_folder = (node->ChildCount > 0);
5243 if (is_folder)
5244 {
5245 bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags);
5246 ImGui::TableNextColumn();
5247 ImGui::TextDisabled("--");
5248 ImGui::TableNextColumn();
5249 ImGui::TextUnformatted(node->Type);
5250 if (open)
5251 {
5252 for (int child_n = 0; child_n < node->ChildCount; child_n++)
5253 DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
5254 ImGui::TreePop();
5255 }
5256 }
5257 else
5258 {
5259 ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen);
5260 ImGui::TableNextColumn();
5261 ImGui::Text("%d", node->Size);
5262 ImGui::TableNextColumn();
5263 ImGui::TextUnformatted(node->Type);
5264 }
5265 }
5266 };
5267 static const MyTreeNode nodes[] =
5268 {
5269 { "Root", "Folder", -1, 1, 3 }, // 0
5270 { "Music", "Folder", -1, 4, 2 }, // 1
5271 { "Textures", "Folder", -1, 6, 3 }, // 2
5272 { "desktop.ini", "System file", 1024, -1,-1 }, // 3
5273 { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4
5274 { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5
5275 { "Image001.png", "Image file", 203128, -1,-1 }, // 6
5276 { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7
5277 { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8
5278 };
5279
5280 MyTreeNode::DisplayNode(&nodes[0], nodes);
5281
5282 ImGui::EndTable();
5283 }
5284 ImGui::TreePop();
5285 }
5286
5287 if (open_action != -1)
5288 ImGui::SetNextItemOpen(open_action != 0);
5289 IMGUI_DEMO_MARKER("Tables/Item width");
5290 if (ImGui::TreeNode("Item width"))
5291 {
5292 HelpMarker(
5293 "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
5294 "Note that on auto-resizing non-resizable fixed columns, querying the content width for "
5295 "e.g. right-alignment doesn't make sense.");
5296 if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
5297 {
5298 ImGui::TableSetupColumn("small");
5299 ImGui::TableSetupColumn("half");
5300 ImGui::TableSetupColumn("right-align");
5301 ImGui::TableHeadersRow();
5302
5303 for (int row = 0; row < 3; row++)
5304 {
5305 ImGui::TableNextRow();
5306 if (row == 0)
5307 {
5308 // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
5309 ImGui::TableSetColumnIndex(0);
5310 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
5311 ImGui::TableSetColumnIndex(1);
5312 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
5313 ImGui::TableSetColumnIndex(2);
5314 ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
5315 }
5316
5317 // Draw our contents
5318 static float dummy_f = 0.0f;
5319 ImGui::PushID(row);
5320 ImGui::TableSetColumnIndex(0);
5321 ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
5322 ImGui::TableSetColumnIndex(1);
5323 ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
5324 ImGui::TableSetColumnIndex(2);
5325 ImGui::SliderFloat("##float2", &dummy_f, 0.0f, 1.0f); // No visible label since right-aligned
5326 ImGui::PopID();
5327 }
5328 ImGui::EndTable();
5329 }
5330 ImGui::TreePop();
5331 }
5332
5333 // Demonstrate using TableHeader() calls instead of TableHeadersRow()
5334 if (open_action != -1)
5335 ImGui::SetNextItemOpen(open_action != 0);
5336 IMGUI_DEMO_MARKER("Tables/Custom headers");
5337 if (ImGui::TreeNode("Custom headers"))
5338 {
5339 const int COLUMNS_COUNT = 3;
5340 if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
5341 {
5342 ImGui::TableSetupColumn("Apricot");
5343 ImGui::TableSetupColumn("Banana");
5344 ImGui::TableSetupColumn("Cherry");
5345
5346 // Dummy entire-column selection storage
5347 // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
5348 static bool column_selected[3] = {};
5349
5350 // Instead of calling TableHeadersRow() we'll submit custom headers ourselves
5351 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
5352 for (int column = 0; column < COLUMNS_COUNT; column++)
5353 {
5354 ImGui::TableSetColumnIndex(column);
5355 const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
5356 ImGui::PushID(column);
5357 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
5358 ImGui::Checkbox("##checkall", &column_selected[column]);
5359 ImGui::PopStyleVar();
5360 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
5361 ImGui::TableHeader(column_name);
5362 ImGui::PopID();
5363 }
5364
5365 for (int row = 0; row < 5; row++)
5366 {
5367 ImGui::TableNextRow();
5368 for (int column = 0; column < 3; column++)
5369 {
5370 char buf[32];
5371 sprintf(buf, "Cell %d,%d", column, row);
5372 ImGui::TableSetColumnIndex(column);
5373 ImGui::Selectable(buf, column_selected[column]);
5374 }
5375 }
5376 ImGui::EndTable();
5377 }
5378 ImGui::TreePop();
5379 }
5380
5381 // Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
5382 if (open_action != -1)
5383 ImGui::SetNextItemOpen(open_action != 0);
5384 IMGUI_DEMO_MARKER("Tables/Angled headers");
5385 if (ImGui::TreeNode("Angled headers"))
5386 {
5387 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" };
5388 const int columns_count = IM_ARRAYSIZE(column_names);
5389 const int rows_count = 12;
5390
5391 static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
5392 static ImGuiTableColumnFlags column_flags = ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed;
5393 static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
5394 static int frozen_cols = 1;
5395 static int frozen_rows = 2;
5396 ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
5397 ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
5398 ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
5399 ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
5400 ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
5401 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
5402 ImGui::SliderInt("Frozen columns", &frozen_cols, 0, 2);
5403 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
5404 ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);
5405 ImGui::CheckboxFlags("Disable header contributing to column width", &column_flags, ImGuiTableColumnFlags_NoHeaderWidth);
5406
5407 if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
5408 {
5409 ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
5410 for (int n = 1; n < columns_count; n++)
5411 ImGui::TableSetupColumn(column_names[n], column_flags);
5412 ImGui::TableSetupScrollFreeze(frozen_cols, frozen_rows);
5413
5414 ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
5415 ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions.
5416 for (int row = 0; row < rows_count; row++)
5417 {
5418 ImGui::PushID(row);
5419 ImGui::TableNextRow();
5420 ImGui::TableSetColumnIndex(0);
5421 ImGui::AlignTextToFramePadding();
5422 ImGui::Text("Track %d", row);
5423 for (int column = 1; column < columns_count; column++)
5424 if (ImGui::TableSetColumnIndex(column))
5425 {
5426 ImGui::PushID(column);
5427 ImGui::Checkbox("", &bools[row * columns_count + column]);
5428 ImGui::PopID();
5429 }
5430 ImGui::PopID();
5431 }
5432 ImGui::EndTable();
5433 }
5434 ImGui::TreePop();
5435 }
5436
5437 // Demonstrate creating custom context menus inside columns,
5438 // while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
5439 if (open_action != -1)
5440 ImGui::SetNextItemOpen(open_action != 0);
5441 IMGUI_DEMO_MARKER("Tables/Context menus");
5442 if (ImGui::TreeNode("Context menus"))
5443 {
5444 HelpMarker(
5445 "By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\n"
5446 "Using ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
5447 static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
5448
5449 PushStyleCompact();
5450 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
5451 PopStyleCompact();
5452
5453 // Context Menus: first example
5454 // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
5455 // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
5456 const int COLUMNS_COUNT = 3;
5457 if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
5458 {
5459 ImGui::TableSetupColumn("One");
5460 ImGui::TableSetupColumn("Two");
5461 ImGui::TableSetupColumn("Three");
5462
5463 // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
5464 ImGui::TableHeadersRow();
5465
5466 // Submit dummy contents
5467 for (int row = 0; row < 4; row++)
5468 {
5469 ImGui::TableNextRow();
5470 for (int column = 0; column < COLUMNS_COUNT; column++)
5471 {
5472 ImGui::TableSetColumnIndex(column);
5473 ImGui::Text("Cell %d,%d", column, row);
5474 }
5475 }
5476 ImGui::EndTable();
5477 }
5478
5479 // Context Menus: second example
5480 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
5481 // [2.2] Right-click on the ".." to open a custom popup
5482 // [2.3] Right-click in columns to open another custom popup
5483 HelpMarker(
5484 "Demonstrate mixing table context menu (over header), item context button (over button) "
5485 "and custom per-colunm context menu (over column body).");
5486 ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
5487 if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
5488 {
5489 ImGui::TableSetupColumn("One");
5490 ImGui::TableSetupColumn("Two");
5491 ImGui::TableSetupColumn("Three");
5492
5493 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
5494 ImGui::TableHeadersRow();
5495 for (int row = 0; row < 4; row++)
5496 {
5497 ImGui::TableNextRow();
5498 for (int column = 0; column < COLUMNS_COUNT; column++)
5499 {
5500 // Submit dummy contents
5501 ImGui::TableSetColumnIndex(column);
5502 ImGui::Text("Cell %d,%d", column, row);
5503 ImGui::SameLine();
5504
5505 // [2.2] Right-click on the ".." to open a custom popup
5506 ImGui::PushID(row * COLUMNS_COUNT + column);
5507 ImGui::SmallButton("..");
5508 if (ImGui::BeginPopupContextItem())
5509 {
5510 ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
5511 if (ImGui::Button("Close"))
5512 ImGui::CloseCurrentPopup();
5513 ImGui::EndPopup();
5514 }
5515 ImGui::PopID();
5516 }
5517 }
5518
5519 // [2.3] Right-click anywhere in columns to open another custom popup
5520 // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
5521 // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
5522 int hovered_column = -1;
5523 for (int column = 0; column < COLUMNS_COUNT + 1; column++)
5524 {
5525 ImGui::PushID(column);
5526 if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
5527 hovered_column = column;
5528 if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
5529 ImGui::OpenPopup("MyPopup");
5530 if (ImGui::BeginPopup("MyPopup"))
5531 {
5532 if (column == COLUMNS_COUNT)
5533 ImGui::Text("This is a custom popup for unused space after the last column.");
5534 else
5535 ImGui::Text("This is a custom popup for Column %d", column);
5536 if (ImGui::Button("Close"))
5537 ImGui::CloseCurrentPopup();
5538 ImGui::EndPopup();
5539 }
5540 ImGui::PopID();
5541 }
5542
5543 ImGui::EndTable();
5544 ImGui::Text("Hovered column: %d", hovered_column);
5545 }
5546 ImGui::TreePop();
5547 }
5548
5549 // Demonstrate creating multiple tables with the same ID
5550 if (open_action != -1)
5551 ImGui::SetNextItemOpen(open_action != 0);
5552 IMGUI_DEMO_MARKER("Tables/Synced instances");
5553 if (ImGui::TreeNode("Synced instances"))
5554 {
5555 HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
5556
5557 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings;
5558 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5559 ImGui::CheckboxFlags("ImGuiTableFlags_SizingFixedFit", &flags, ImGuiTableFlags_SizingFixedFit);
5560 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5561 for (int n = 0; n < 3; n++)
5562 {
5563 char buf[32];
5564 sprintf(buf, "Synced Table %d", n);
5565 bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
5566 if (open && ImGui::BeginTable("Table", 3, flags, ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 5)))
5567 {
5568 ImGui::TableSetupColumn("One");
5569 ImGui::TableSetupColumn("Two");
5570 ImGui::TableSetupColumn("Three");
5571 ImGui::TableHeadersRow();
5572 const int cell_count = (n == 1) ? 27 : 9; // Make second table have a scrollbar to verify that additional decoration is not affecting column positions.
5573 for (int cell = 0; cell < cell_count; cell++)
5574 {
5575 ImGui::TableNextColumn();
5576 ImGui::Text("this cell %d", cell);
5577 }
5578 ImGui::EndTable();
5579 }
5580 }
5581 ImGui::TreePop();
5582 }
5583
5584 // Demonstrate using Sorting facilities
5585 // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
5586 // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
5587 static const char* template_items_names[] =
5588 {
5589 "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
5590 "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
5591 };
5592 if (open_action != -1)
5593 ImGui::SetNextItemOpen(open_action != 0);
5594 IMGUI_DEMO_MARKER("Tables/Sorting");
5595 if (ImGui::TreeNode("Sorting"))
5596 {
5597 // Create item list
5598 static ImVector<MyItem> items;
5599 if (items.Size == 0)
5600 {
5601 items.resize(50, MyItem());
5602 for (int n = 0; n < items.Size; n++)
5603 {
5604 const int template_n = n % IM_ARRAYSIZE(template_items_names);
5605 MyItem& item = items[n];
5606 item.ID = n;
5607 item.Name = template_items_names[template_n];
5608 item.Quantity = (n * n - n) % 20; // Assign default quantities
5609 }
5610 }
5611
5612 // Options
5613 static ImGuiTableFlags flags =
5614 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
5615 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
5616 | ImGuiTableFlags_ScrollY;
5617 PushStyleCompact();
5618 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
5619 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
5620 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
5621 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
5622 PopStyleCompact();
5623
5624 if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
5625 {
5626 // Declare columns
5627 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
5628 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
5629 // Demonstrate using a mixture of flags among available sort-related flags:
5630 // - ImGuiTableColumnFlags_DefaultSort
5631 // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
5632 // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
5633 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID);
5634 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
5635 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
5636 ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
5637 ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
5638 ImGui::TableHeadersRow();
5639
5640 // Sort our data if sort specs have been changed!
5641 if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
5642 if (sort_specs->SpecsDirty)
5643 {
5644 MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
5645 sort_specs->SpecsDirty = false;
5646 }
5647
5648 // Demonstrate using clipper for large vertical lists
5649 ImGuiListClipper clipper;
5650 clipper.Begin(items.Size);
5651 while (clipper.Step())
5652 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
5653 {
5654 // Display a data item
5655 MyItem* item = &items[row_n];
5656 ImGui::PushID(item->ID);
5657 ImGui::TableNextRow();
5658 ImGui::TableNextColumn();
5659 ImGui::Text("%04d", item->ID);
5660 ImGui::TableNextColumn();
5661 ImGui::TextUnformatted(item->Name);
5662 ImGui::TableNextColumn();
5663 ImGui::SmallButton("None");
5664 ImGui::TableNextColumn();
5665 ImGui::Text("%d", item->Quantity);
5666 ImGui::PopID();
5667 }
5668 ImGui::EndTable();
5669 }
5670 ImGui::TreePop();
5671 }
5672
5673 // In this example we'll expose most table flags and settings.
5674 // For specific flags and settings refer to the corresponding section for more detailed explanation.
5675 // This section is mostly useful to experiment with combining certain flags or settings with each others.
5676 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
5677 if (open_action != -1)
5678 ImGui::SetNextItemOpen(open_action != 0);
5679 IMGUI_DEMO_MARKER("Tables/Advanced");
5680 if (ImGui::TreeNode("Advanced"))
5681 {
5682 static ImGuiTableFlags flags =
5683 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
5684 | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
5685 | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
5686 | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
5687 | ImGuiTableFlags_SizingFixedFit;
5688 static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;
5689
5690 enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
5691 static int contents_type = CT_SelectableSpanRow;
5692 const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
5693 static int freeze_cols = 1;
5694 static int freeze_rows = 1;
5695 static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
5696 static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
5697 static float row_min_height = 0.0f; // Auto
5698 static float inner_width_with_scroll = 0.0f; // Auto-extend
5699 static bool outer_size_enabled = true;
5700 static bool show_headers = true;
5701 static bool show_wrapped_text = false;
5702 //static ImGuiTextFilter filter;
5703 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affect column sizing
5704 if (ImGui::TreeNode("Options"))
5705 {
5706 // Make the UI compact because there are so many fields
5707 PushStyleCompact();
5708 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
5709
5710 if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
5711 {
5712 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5713 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
5714 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
5715 ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
5716 ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
5717 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
5718 ImGui::TreePop();
5719 }
5720
5721 if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
5722 {
5723 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5724 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5725 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
5726 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
5727 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
5728 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
5729 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
5730 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appear in Headers");
5731 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers)");
5732 ImGui::TreePop();
5733 }
5734
5735 if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
5736 {
5737 EditTableSizingFlags(&flags);
5738 ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
5739 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5740 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
5741 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
5742 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
5743 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
5744 ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
5745 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
5746 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
5747 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
5748 ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.");
5749 ImGui::TreePop();
5750 }
5751
5752 if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
5753 {
5754 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
5755 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
5756 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
5757 ImGui::TreePop();
5758 }
5759
5760 if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
5761 {
5762 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5763 ImGui::SameLine();
5764 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5765 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5766 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5767 ImGui::SameLine();
5768 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5769 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5770 ImGui::TreePop();
5771 }
5772
5773 if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
5774 {
5775 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
5776 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
5777 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
5778 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
5779 ImGui::TreePop();
5780 }
5781
5782 if (ImGui::TreeNodeEx("Headers:", ImGuiTreeNodeFlags_DefaultOpen))
5783 {
5784 ImGui::Checkbox("show_headers", &show_headers);
5785 ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
5786 ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
5787 ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
5788 ImGui::TreePop();
5789 }
5790
5791 if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
5792 {
5793 ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
5794
5795 ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
5796 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
5797 ImGui::Checkbox("outer_size", &outer_size_enabled);
5798 ImGui::SameLine();
5799 HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
5800 "- The table is output directly in the parent window.\n"
5801 "- OuterSize.x < 0.0f will right-align the table.\n"
5802 "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch columns.\n"
5803 "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
5804
5805 // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
5806 // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
5807 ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
5808
5809 ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
5810 ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
5811
5812 ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
5813 ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
5814 //filter.Draw("filter");
5815 ImGui::TreePop();
5816 }
5817
5818 ImGui::PopItemWidth();
5819 PopStyleCompact();
5820 ImGui::Spacing();
5821 ImGui::TreePop();
5822 }
5823
5824 // Update item list if we changed the number of items
5825 static ImVector<MyItem> items;
5826 static ImVector<int> selection;
5827 static bool items_need_sort = false;
5828 if (items.Size != items_count)
5829 {
5830 items.resize(items_count, MyItem());
5831 for (int n = 0; n < items_count; n++)
5832 {
5833 const int template_n = n % IM_ARRAYSIZE(template_items_names);
5834 MyItem& item = items[n];
5835 item.ID = n;
5836 item.Name = template_items_names[template_n];
5837 item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
5838 }
5839 }
5840
5841 const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
5842 const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
5843 ImVec2 table_scroll_cur, table_scroll_max; // For debug display
5844 const ImDrawList* table_draw_list = NULL; // "
5845
5846 // Submit table
5847 const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
5848 if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
5849 {
5850 // Declare columns
5851 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
5852 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
5853 ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
5854 ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
5855 ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
5856 ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
5857 ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
5858 ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
5859 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
5860
5861 // Sort our data if sort specs have been changed!
5862 ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
5863 if (sort_specs && sort_specs->SpecsDirty)
5864 items_need_sort = true;
5865 if (sort_specs && items_need_sort && items.Size > 1)
5866 {
5867 MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
5868 sort_specs->SpecsDirty = false;
5869 }
5870 items_need_sort = false;
5871
5872 // Take note of whether we are currently sorting based on the Quantity field,
5873 // we will use this to trigger sorting when we know the data of this column has been modified.
5874 const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
5875
5876 // Show headers
5877 if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
5878 ImGui::TableAngledHeadersRow();
5879 if (show_headers)
5880 ImGui::TableHeadersRow();
5881
5882 // Show data
5883 // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
5884 ImGui::PushButtonRepeat(true);
5885#if 1
5886 // Demonstrate using clipper for large vertical lists
5887 ImGuiListClipper clipper;
5888 clipper.Begin(items.Size);
5889 while (clipper.Step())
5890 {
5891 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
5892#else
5893 // Without clipper
5894 {
5895 for (int row_n = 0; row_n < items.Size; row_n++)
5896#endif
5897 {
5898 MyItem* item = &items[row_n];
5899 //if (!filter.PassFilter(item->Name))
5900 // continue;
5901
5902 const bool item_is_selected = selection.contains(item->ID);
5903 ImGui::PushID(item->ID);
5904 ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
5905
5906 // For the demo purpose we can select among different type of items submitted in the first column
5907 ImGui::TableSetColumnIndex(0);
5908 char label[32];
5909 sprintf(label, "%04d", item->ID);
5910 if (contents_type == CT_Text)
5912 else if (contents_type == CT_Button)
5913 ImGui::Button(label);
5914 else if (contents_type == CT_SmallButton)
5915 ImGui::SmallButton(label);
5916 else if (contents_type == CT_FillButton)
5917 ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
5918 else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
5919 {
5920 ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
5921 if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
5922 {
5923 if (ImGui::GetIO().KeyCtrl)
5924 {
5925 if (item_is_selected)
5926 selection.find_erase_unsorted(item->ID);
5927 else
5928 selection.push_back(item->ID);
5929 }
5930 else
5931 {
5932 selection.clear();
5933 selection.push_back(item->ID);
5934 }
5935 }
5936 }
5937
5938 if (ImGui::TableSetColumnIndex(1))
5939 ImGui::TextUnformatted(item->Name);
5940
5941 // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
5942 // and we are currently sorting on the column showing the Quantity.
5943 // To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
5944 // You will probably need some extra logic if you want to automatically sort when a specific entry changes.
5945 if (ImGui::TableSetColumnIndex(2))
5946 {
5947 if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
5948 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
5949 ImGui::SameLine();
5950 if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
5951 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
5952 }
5953
5954 if (ImGui::TableSetColumnIndex(3))
5955 ImGui::Text("%d", item->Quantity);
5956
5957 ImGui::TableSetColumnIndex(4);
5958 if (show_wrapped_text)
5959 ImGui::TextWrapped("Lorem ipsum dolor sit amet");
5960 else
5961 ImGui::Text("Lorem ipsum dolor sit amet");
5962
5963 if (ImGui::TableSetColumnIndex(5))
5964 ImGui::Text("1234");
5965
5966 ImGui::PopID();
5967 }
5968 }
5969 ImGui::PopButtonRepeat();
5970
5971 // Store some info to display debug details below
5972 table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
5973 table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
5974 table_draw_list = ImGui::GetWindowDrawList();
5975 ImGui::EndTable();
5976 }
5977 static bool show_debug_details = false;
5978 ImGui::Checkbox("Debug details", &show_debug_details);
5979 if (show_debug_details && table_draw_list)
5980 {
5981 ImGui::SameLine(0.0f, 0.0f);
5982 const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
5983 if (table_draw_list == parent_draw_list)
5984 ImGui::Text(": DrawCmd: +%d (in same window)",
5985 table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
5986 else
5987 ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
5988 table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
5989 }
5990 ImGui::TreePop();
5991 }
5992
5993 ImGui::PopID();
5994
5995 ShowDemoWindowColumns();
5996
5997 if (disable_indent)
5998 ImGui::PopStyleVar();
5999}
6000
6001// Demonstrate old/legacy Columns API!
6002// [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
6003static void ShowDemoWindowColumns()
6004{
6005 IMGUI_DEMO_MARKER("Columns (legacy API)");
6006 bool open = ImGui::TreeNode("Legacy Columns API");
6007 ImGui::SameLine();
6008 HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
6009 if (!open)
6010 return;
6011
6012 // Basic columns
6013 IMGUI_DEMO_MARKER("Columns (legacy API)/Basic");
6014 if (ImGui::TreeNode("Basic"))
6015 {
6016 ImGui::Text("Without border:");
6017 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
6018 ImGui::Separator();
6019 for (int n = 0; n < 14; n++)
6020 {
6021 char label[32];
6022 sprintf(label, "Item %d", n);
6023 if (ImGui::Selectable(label)) {}
6024 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
6025 ImGui::NextColumn();
6026 }
6027 ImGui::Columns(1);
6028 ImGui::Separator();
6029
6030 ImGui::Text("With border:");
6031 ImGui::Columns(4, "mycolumns"); // 4-ways, with border
6032 ImGui::Separator();
6033 ImGui::Text("ID"); ImGui::NextColumn();
6034 ImGui::Text("Name"); ImGui::NextColumn();
6035 ImGui::Text("Path"); ImGui::NextColumn();
6036 ImGui::Text("Hovered"); ImGui::NextColumn();
6037 ImGui::Separator();
6038 const char* names[3] = { "One", "Two", "Three" };
6039 const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
6040 static int selected = -1;
6041 for (int i = 0; i < 3; i++)
6042 {
6043 char label[32];
6044 sprintf(label, "%04d", i);
6045 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
6046 selected = i;
6047 bool hovered = ImGui::IsItemHovered();
6048 ImGui::NextColumn();
6049 ImGui::Text(names[i]); ImGui::NextColumn();
6050 ImGui::Text(paths[i]); ImGui::NextColumn();
6051 ImGui::Text("%d", hovered); ImGui::NextColumn();
6052 }
6053 ImGui::Columns(1);
6054 ImGui::Separator();
6055 ImGui::TreePop();
6056 }
6057
6058 IMGUI_DEMO_MARKER("Columns (legacy API)/Borders");
6059 if (ImGui::TreeNode("Borders"))
6060 {
6061 // NB: Future columns API should allow automatic horizontal borders.
6062 static bool h_borders = true;
6063 static bool v_borders = true;
6064 static int columns_count = 4;
6065 const int lines_count = 3;
6066 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
6067 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
6068 if (columns_count < 2)
6069 columns_count = 2;
6070 ImGui::SameLine();
6071 ImGui::Checkbox("horizontal", &h_borders);
6072 ImGui::SameLine();
6073 ImGui::Checkbox("vertical", &v_borders);
6074 ImGui::Columns(columns_count, NULL, v_borders);
6075 for (int i = 0; i < columns_count * lines_count; i++)
6076 {
6077 if (h_borders && ImGui::GetColumnIndex() == 0)
6078 ImGui::Separator();
6079 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
6080 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
6081 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
6082 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
6083 ImGui::Text("Long text that is likely to clip");
6084 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
6085 ImGui::NextColumn();
6086 }
6087 ImGui::Columns(1);
6088 if (h_borders)
6089 ImGui::Separator();
6090 ImGui::TreePop();
6091 }
6092
6093 // Create multiple items in a same cell before switching to next column
6094 IMGUI_DEMO_MARKER("Columns (legacy API)/Mixed items");
6095 if (ImGui::TreeNode("Mixed items"))
6096 {
6097 ImGui::Columns(3, "mixed");
6098 ImGui::Separator();
6099
6100 ImGui::Text("Hello");
6101 ImGui::Button("Banana");
6102 ImGui::NextColumn();
6103
6104 ImGui::Text("ImGui");
6105 ImGui::Button("Apple");
6106 static float foo = 1.0f;
6107 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
6108 ImGui::Text("An extra line here.");
6109 ImGui::NextColumn();
6110
6111 ImGui::Text("Sailor");
6112 ImGui::Button("Corniflower");
6113 static float bar = 1.0f;
6114 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
6115 ImGui::NextColumn();
6116
6117 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
6118 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
6119 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
6120 ImGui::Columns(1);
6121 ImGui::Separator();
6122 ImGui::TreePop();
6123 }
6124
6125 // Word wrapping
6126 IMGUI_DEMO_MARKER("Columns (legacy API)/Word-wrapping");
6127 if (ImGui::TreeNode("Word-wrapping"))
6128 {
6129 ImGui::Columns(2, "word-wrapping");
6130 ImGui::Separator();
6131 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
6132 ImGui::TextWrapped("Hello Left");
6133 ImGui::NextColumn();
6134 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
6135 ImGui::TextWrapped("Hello Right");
6136 ImGui::Columns(1);
6137 ImGui::Separator();
6138 ImGui::TreePop();
6139 }
6140
6141 IMGUI_DEMO_MARKER("Columns (legacy API)/Horizontal Scrolling");
6142 if (ImGui::TreeNode("Horizontal Scrolling"))
6143 {
6144 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
6145 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
6146 ImGui::BeginChild("##ScrollingRegion", child_size, ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar);
6147 ImGui::Columns(10);
6148
6149 // Also demonstrate using clipper for large vertical lists
6150 int ITEMS_COUNT = 2000;
6151 ImGuiListClipper clipper;
6152 clipper.Begin(ITEMS_COUNT);
6153 while (clipper.Step())
6154 {
6155 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
6156 for (int j = 0; j < 10; j++)
6157 {
6158 ImGui::Text("Line %d Column %d...", i, j);
6159 ImGui::NextColumn();
6160 }
6161 }
6162 ImGui::Columns(1);
6163 ImGui::EndChild();
6164 ImGui::TreePop();
6165 }
6166
6167 IMGUI_DEMO_MARKER("Columns (legacy API)/Tree");
6168 if (ImGui::TreeNode("Tree"))
6169 {
6170 ImGui::Columns(2, "tree", true);
6171 for (int x = 0; x < 3; x++)
6172 {
6173 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
6174 ImGui::NextColumn();
6175 ImGui::Text("Node contents");
6176 ImGui::NextColumn();
6177 if (open1)
6178 {
6179 for (int y = 0; y < 3; y++)
6180 {
6181 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
6182 ImGui::NextColumn();
6183 ImGui::Text("Node contents");
6184 if (open2)
6185 {
6186 ImGui::Text("Even more contents");
6187 if (ImGui::TreeNode("Tree in column"))
6188 {
6189 ImGui::Text("The quick brown fox jumps over the lazy dog");
6190 ImGui::TreePop();
6191 }
6192 }
6193 ImGui::NextColumn();
6194 if (open2)
6195 ImGui::TreePop();
6196 }
6197 ImGui::TreePop();
6198 }
6199 }
6200 ImGui::Columns(1);
6201 ImGui::TreePop();
6202 }
6203
6204 ImGui::TreePop();
6205}
6206
6207static void ShowDemoWindowInputs()
6208{
6209 IMGUI_DEMO_MARKER("Inputs & Focus");
6210 if (ImGui::CollapsingHeader("Inputs & Focus"))
6211 {
6212 ImGuiIO& io = ImGui::GetIO();
6213
6214 // Display inputs submitted to ImGuiIO
6215 IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
6216 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
6217 if (ImGui::TreeNode("Inputs"))
6218 {
6219 HelpMarker(
6220 "This is a simplified view. See more detailed input state:\n"
6221 "- in 'Tools->Metrics/Debugger->Inputs'.\n"
6222 "- in 'Tools->Debug Log->IO'.");
6223 if (ImGui::IsMousePosValid())
6224 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
6225 else
6226 ImGui::Text("Mouse pos: <INVALID>");
6227 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
6228 ImGui::Text("Mouse down:");
6229 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
6230 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
6231
6232 // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows
6233 // displaying the data for old/new backends.
6234 // User code should never have to go through such hoops!
6235 // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
6236#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
6237 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
6238 ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN;
6239#else
6240 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
6241 ImGuiKey start_key = (ImGuiKey)0;
6242#endif
6243 ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); }
6244 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
6245 ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
6246
6247 ImGui::TreePop();
6248 }
6249
6250 // Display ImGuiIO output flags
6251 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
6252 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
6253 if (ImGui::TreeNode("Outputs"))
6254 {
6255 HelpMarker(
6256 "The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
6257 "to instruct your application of how to route inputs. Typically, when a value is true, it means "
6258 "Dear ImGui wants the corresponding inputs and we expect the underlying application to ignore them.\n\n"
6259 "The most typical case is: when hovering a window, Dear ImGui set io.WantCaptureMouse to true, "
6260 "and underlying application should ignore mouse inputs (in practice there are many and more subtle "
6261 "rules leading to how those flags are set).");
6262 ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
6263 ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
6264 ImGui::Text("io.WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
6265 ImGui::Text("io.WantTextInput: %d", io.WantTextInput);
6266 ImGui::Text("io.WantSetMousePos: %d", io.WantSetMousePos);
6267 ImGui::Text("io.NavActive: %d, io.NavVisible: %d", io.NavActive, io.NavVisible);
6268
6269 IMGUI_DEMO_MARKER("Inputs & Focus/Outputs/WantCapture override");
6270 if (ImGui::TreeNode("WantCapture override"))
6271 {
6272 HelpMarker(
6273 "Hovering the colored canvas will override io.WantCaptureXXX fields.\n"
6274 "Notice how normally (when set to none), the value of io.WantCaptureKeyboard would be false when hovering "
6275 "and true when clicking.");
6276 static int capture_override_mouse = -1;
6277 static int capture_override_keyboard = -1;
6278 const char* capture_override_desc[] = { "None", "Set to false", "Set to true" };
6279 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
6280 ImGui::SliderInt("SetNextFrameWantCaptureMouse() on hover", &capture_override_mouse, -1, +1, capture_override_desc[capture_override_mouse + 1], ImGuiSliderFlags_AlwaysClamp);
6281 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);
6282 ImGui::SliderInt("SetNextFrameWantCaptureKeyboard() on hover", &capture_override_keyboard, -1, +1, capture_override_desc[capture_override_keyboard + 1], ImGuiSliderFlags_AlwaysClamp);
6283
6284 ImGui::ColorButton("##panel", ImVec4(0.7f, 0.1f, 0.7f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, ImVec2(128.0f, 96.0f)); // Dummy item
6285 if (ImGui::IsItemHovered() && capture_override_mouse != -1)
6286 ImGui::SetNextFrameWantCaptureMouse(capture_override_mouse == 1);
6287 if (ImGui::IsItemHovered() && capture_override_keyboard != -1)
6288 ImGui::SetNextFrameWantCaptureKeyboard(capture_override_keyboard == 1);
6289
6290 ImGui::TreePop();
6291 }
6292 ImGui::TreePop();
6293 }
6294
6295 // Display mouse cursors
6296 IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
6297 if (ImGui::TreeNode("Mouse Cursors"))
6298 {
6299 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
6300 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
6301
6302 ImGuiMouseCursor current = ImGui::GetMouseCursor();
6303 ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
6304 ImGui::BeginDisabled(true);
6305 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
6306 ImGui::EndDisabled();
6307
6308 ImGui::Text("Hover to see mouse cursors:");
6309 ImGui::SameLine(); HelpMarker(
6310 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
6311 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
6312 "otherwise your backend needs to handle it.");
6313 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
6314 {
6315 char label[32];
6316 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
6317 ImGui::Bullet(); ImGui::Selectable(label, false);
6318 if (ImGui::IsItemHovered())
6319 ImGui::SetMouseCursor(i);
6320 }
6321 ImGui::TreePop();
6322 }
6323
6324 IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
6325 if (ImGui::TreeNode("Tabbing"))
6326 {
6327 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
6328 static char buf[32] = "hello";
6329 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
6330 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
6331 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
6332 ImGui::PushTabStop(false);
6333 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
6334 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
6335 ImGui::PopTabStop();
6336 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
6337 ImGui::TreePop();
6338 }
6339
6340 IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
6341 if (ImGui::TreeNode("Focus from code"))
6342 {
6343 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
6344 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
6345 bool focus_3 = ImGui::Button("Focus on 3");
6346 int has_focus = 0;
6347 static char buf[128] = "click on a button to set focus";
6348
6349 if (focus_1) ImGui::SetKeyboardFocusHere();
6350 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
6351 if (ImGui::IsItemActive()) has_focus = 1;
6352
6353 if (focus_2) ImGui::SetKeyboardFocusHere();
6354 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
6355 if (ImGui::IsItemActive()) has_focus = 2;
6356
6357 ImGui::PushTabStop(false);
6358 if (focus_3) ImGui::SetKeyboardFocusHere();
6359 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
6360 if (ImGui::IsItemActive()) has_focus = 3;
6361 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
6362 ImGui::PopTabStop();
6363
6364 if (has_focus)
6365 ImGui::Text("Item with focus: %d", has_focus);
6366 else
6367 ImGui::Text("Item with focus: <none>");
6368
6369 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
6370 static float f3[3] = { 0.0f, 0.0f, 0.0f };
6371 int focus_ahead = -1;
6372 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
6373 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
6374 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
6375 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
6376 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
6377
6378 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
6379 ImGui::TreePop();
6380 }
6381
6382 IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
6383 if (ImGui::TreeNode("Dragging"))
6384 {
6385 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
6386 for (int button = 0; button < 3; button++)
6387 {
6388 ImGui::Text("IsMouseDragging(%d):", button);
6389 ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button));
6390 ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
6391 ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
6392 }
6393
6394 ImGui::Button("Drag Me");
6395 if (ImGui::IsItemActive())
6396 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
6397
6398 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
6399 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
6400 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
6401 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
6402 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
6403 ImVec2 mouse_delta = io.MouseDelta;
6404 ImGui::Text("GetMouseDragDelta(0):");
6405 ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
6406 ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
6407 ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
6408 ImGui::TreePop();
6409 }
6410 }
6411}
6412
6413//-----------------------------------------------------------------------------
6414// [SECTION] About Window / ShowAboutWindow()
6415// Access from Dear ImGui Demo -> Tools -> About
6416//-----------------------------------------------------------------------------
6417
6418void ImGui::ShowAboutWindow(bool* p_open)
6419{
6420 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
6421 {
6422 ImGui::End();
6423 return;
6424 }
6425 IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
6426 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
6427 ImGui::Separator();
6428 ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
6429 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
6430 ImGui::Text("If your company uses this, please consider sponsoring the project!");
6431
6432 static bool show_config_info = false;
6433 ImGui::Checkbox("Config/Build Information", &show_config_info);
6434 if (show_config_info)
6435 {
6436 ImGuiIO& io = ImGui::GetIO();
6437 ImGuiStyle& style = ImGui::GetStyle();
6438
6439 bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
6440 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
6441 ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
6442 if (copy_to_clipboard)
6443 {
6444 ImGui::LogToClipboard();
6445 ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
6446 }
6447
6448 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
6449 ImGui::Separator();
6450 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
6451 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
6452#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
6453 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
6454#endif
6455#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
6456 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_KEYIO");
6457#endif
6458#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
6459 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
6460#endif
6461#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
6462 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
6463#endif
6464#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
6465 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
6466#endif
6467#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
6468 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
6469#endif
6470#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
6471 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
6472#endif
6473#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
6474 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
6475#endif
6476#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
6477 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
6478#endif
6479#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
6480 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
6481#endif
6482#ifdef IMGUI_USE_BGRA_PACKED_COLOR
6483 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
6484#endif
6485#ifdef _WIN32
6486 ImGui::Text("define: _WIN32");
6487#endif
6488#ifdef _WIN64
6489 ImGui::Text("define: _WIN64");
6490#endif
6491#ifdef __linux__
6492 ImGui::Text("define: __linux__");
6493#endif
6494#ifdef __APPLE__
6495 ImGui::Text("define: __APPLE__");
6496#endif
6497#ifdef _MSC_VER
6498 ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
6499#endif
6500#ifdef _MSVC_LANG
6501 ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
6502#endif
6503#ifdef __MINGW32__
6504 ImGui::Text("define: __MINGW32__");
6505#endif
6506#ifdef __MINGW64__
6507 ImGui::Text("define: __MINGW64__");
6508#endif
6509#ifdef __GNUC__
6510 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
6511#endif
6512#ifdef __clang_version__
6513 ImGui::Text("define: __clang_version__=%s", __clang_version__);
6514#endif
6515#ifdef __EMSCRIPTEN__
6516 ImGui::Text("define: __EMSCRIPTEN__");
6517#endif
6518#ifdef IMGUI_HAS_VIEWPORT
6519 ImGui::Text("define: IMGUI_HAS_VIEWPORT");
6520#endif
6521#ifdef IMGUI_HAS_DOCK
6522 ImGui::Text("define: IMGUI_HAS_DOCK");
6523#endif
6524 ImGui::Separator();
6525 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
6526 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
6527 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
6528 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
6529 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
6530 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos");
6531 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard");
6532 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
6533 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
6534 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable");
6535 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable");
6536 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports");
6537 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts");
6538 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
6539 if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
6540 if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
6541 if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
6542 if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent");
6543 if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit");
6544 if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift");
6545 if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar");
6546 if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload");
6547 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
6548 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
6549 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
6550 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
6551 if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
6552 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
6553 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
6554 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
6555 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
6556 if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports");
6557 if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
6558 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
6559 if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports");
6560 ImGui::Separator();
6561 ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
6562 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
6563 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
6564 ImGui::Separator();
6565 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
6566 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
6567 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
6568 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
6569 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
6570 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
6571 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
6572
6573 if (copy_to_clipboard)
6574 {
6575 ImGui::LogText("\n```\n");
6576 ImGui::LogFinish();
6577 }
6578 ImGui::EndChild();
6579 }
6580 ImGui::End();
6581}
6582
6583//-----------------------------------------------------------------------------
6584// [SECTION] Style Editor / ShowStyleEditor()
6585//-----------------------------------------------------------------------------
6586// - ShowFontSelector()
6587// - ShowStyleSelector()
6588// - ShowStyleEditor()
6589//-----------------------------------------------------------------------------
6590
6591// Forward declare ShowFontAtlas() which isn't worth putting in public API yet
6592namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
6593
6594// Demo helper function to select among loaded fonts.
6595// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one.
6596void ImGui::ShowFontSelector(const char* label)
6597{
6598 ImGuiIO& io = ImGui::GetIO();
6599 ImFont* font_current = ImGui::GetFont();
6600 if (ImGui::BeginCombo(label, font_current->GetDebugName()))
6601 {
6602 for (ImFont* font : io.Fonts->Fonts)
6603 {
6604 ImGui::PushID((void*)font);
6605 if (ImGui::Selectable(font->GetDebugName(), font == font_current))
6606 io.FontDefault = font;
6607 ImGui::PopID();
6608 }
6609 ImGui::EndCombo();
6610 }
6611 ImGui::SameLine();
6612 HelpMarker(
6613 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
6614 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
6615 "- Read FAQ and docs/FONTS.md for more details.\n"
6616 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
6617}
6618
6619// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
6620// Here we use the simplified Combo() api that packs items into a single literal string.
6621// Useful for quick combo boxes where the choices are known locally.
6622bool ImGui::ShowStyleSelector(const char* label)
6623{
6624 static int style_idx = -1;
6625 if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0"))
6626 {
6627 switch (style_idx)
6628 {
6629 case 0: ImGui::StyleColorsDark(); break;
6630 case 1: ImGui::StyleColorsLight(); break;
6631 case 2: ImGui::StyleColorsClassic(); break;
6632 }
6633 return true;
6634 }
6635 return false;
6636}
6637
6638void ImGui::ShowStyleEditor(ImGuiStyle* ref)
6639{
6640 IMGUI_DEMO_MARKER("Tools/Style Editor");
6641 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
6642 // (without a reference style pointer, we will use one compared locally as a reference)
6643 ImGuiStyle& style = ImGui::GetStyle();
6644 static ImGuiStyle ref_saved_style;
6645
6646 // Default to using internal storage as reference
6647 static bool init = true;
6648 if (init && ref == NULL)
6649 ref_saved_style = style;
6650 init = false;
6651 if (ref == NULL)
6652 ref = &ref_saved_style;
6653
6654 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
6655
6656 if (ImGui::ShowStyleSelector("Colors##Selector"))
6657 ref_saved_style = style;
6658 ImGui::ShowFontSelector("Fonts##Selector");
6659
6660 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
6661 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
6662 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
6663 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
6664 ImGui::SameLine();
6665 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } }
6666 ImGui::SameLine();
6667 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } }
6668
6669 // Save/Revert button
6670 if (ImGui::Button("Save Ref"))
6671 *ref = ref_saved_style = style;
6672 ImGui::SameLine();
6673 if (ImGui::Button("Revert Ref"))
6674 style = *ref;
6675 ImGui::SameLine();
6676 HelpMarker(
6677 "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
6678 "Use \"Export\" below to save them somewhere.");
6679
6680 ImGui::Separator();
6681
6682 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
6683 {
6684 if (ImGui::BeginTabItem("Sizes"))
6685 {
6686 ImGui::SeparatorText("Main");
6687 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
6688 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
6689 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
6690 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
6691 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
6692 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
6693 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
6694 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
6695
6696 ImGui::SeparatorText("Borders");
6697 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
6698 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
6699 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
6700 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
6701 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
6702 ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
6703
6704 ImGui::SeparatorText("Rounding");
6705 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
6706 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
6707 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
6708 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
6709 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
6710 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
6711 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
6712
6713 ImGui::SeparatorText("Tables");
6714 ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
6715 ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);
6716
6717 ImGui::SeparatorText("Widgets");
6718 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
6719 int window_menu_button_position = style.WindowMenuButtonPosition + 1;
6720 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
6721 style.WindowMenuButtonPosition = window_menu_button_position - 1;
6722 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
6723 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
6724 ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
6725 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
6726 ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
6727 ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
6728 ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
6729 ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f");
6730 ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
6731
6732 ImGui::SeparatorText("Docking");
6733 ImGui::SliderFloat("DockingSplitterSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f");
6734
6735 ImGui::SeparatorText("Tooltips");
6736 for (int n = 0; n < 2; n++)
6737 if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav"))
6738 {
6739 ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav;
6740 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone);
6741 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort);
6742 ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal);
6743 ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary);
6744 ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay);
6745 ImGui::TreePop();
6746 }
6747
6748 ImGui::SeparatorText("Misc");
6749 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
6750
6751 ImGui::EndTabItem();
6752 }
6753
6754 if (ImGui::BeginTabItem("Colors"))
6755 {
6756 static int output_dest = 0;
6757 static bool output_only_modified = true;
6758 if (ImGui::Button("Export"))
6759 {
6760 if (output_dest == 0)
6761 ImGui::LogToClipboard();
6762 else
6763 ImGui::LogToTTY();
6764 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
6765 for (int i = 0; i < ImGuiCol_COUNT; i++)
6766 {
6767 const ImVec4& col = style.Colors[i];
6768 const char* name = ImGui::GetStyleColorName(i);
6769 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
6770 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
6771 name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
6772 }
6773 ImGui::LogFinish();
6774 }
6775 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
6776 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
6777
6778 static ImGuiTextFilter filter;
6779 filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
6780
6781 static ImGuiColorEditFlags alpha_flags = 0;
6782 if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
6783 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
6784 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
6785 HelpMarker(
6786 "In the color list:\n"
6787 "Left-click on color square to open color picker,\n"
6788 "Right-click to open edit options menu.");
6789
6790 ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
6791 ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
6792 ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
6793 for (int i = 0; i < ImGuiCol_COUNT; i++)
6794 {
6795 const char* name = ImGui::GetStyleColorName(i);
6796 if (!filter.PassFilter(name))
6797 continue;
6798 ImGui::PushID(i);
6799#ifndef IMGUI_DISABLE_DEBUG_TOOLS
6800 if (ImGui::Button("?"))
6801 ImGui::DebugFlashStyleColor((ImGuiCol)i);
6802 ImGui::SetItemTooltip("Flash given color to identify places where it is used.");
6803 ImGui::SameLine();
6804#endif
6805 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
6806 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
6807 {
6808 // Tips: in a real user application, you may want to merge and use an icon font into the main font,
6809 // so instead of "Save"/"Revert" you'd use icons!
6810 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
6811 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
6812 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
6813 }
6814 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
6816 ImGui::PopID();
6817 }
6818 ImGui::PopItemWidth();
6819 ImGui::EndChild();
6820
6821 ImGui::EndTabItem();
6822 }
6823
6824 if (ImGui::BeginTabItem("Fonts"))
6825 {
6826 ImGuiIO& io = ImGui::GetIO();
6827 ImFontAtlas* atlas = io.Fonts;
6828 HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
6829 ImGui::ShowFontAtlas(atlas);
6830
6831 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
6832 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
6833 const float MIN_SCALE = 0.3f;
6834 const float MAX_SCALE = 2.0f;
6835 HelpMarker(
6836 "Those are old settings provided for convenience.\n"
6837 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
6838 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
6839 "Using those settings here will give you poor quality results.");
6840 static float window_scale = 1.0f;
6841 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
6842 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
6843 ImGui::SetWindowFontScale(window_scale);
6844 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
6845 ImGui::PopItemWidth();
6846
6847 ImGui::EndTabItem();
6848 }
6849
6850 if (ImGui::BeginTabItem("Rendering"))
6851 {
6852 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
6853 ImGui::SameLine();
6854 HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
6855
6856 ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
6857 ImGui::SameLine();
6858 HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
6859
6860 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
6861 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
6862 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
6863 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
6864
6865 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
6866 ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
6867 const bool show_samples = ImGui::IsItemActive();
6868 if (show_samples)
6869 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
6870 if (show_samples && ImGui::BeginTooltip())
6871 {
6872 ImGui::TextUnformatted("(R = radius, N = number of segments)");
6873 ImGui::Spacing();
6874 ImDrawList* draw_list = ImGui::GetWindowDrawList();
6875 const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x;
6876 for (int n = 0; n < 8; n++)
6877 {
6878 const float RAD_MIN = 5.0f;
6879 const float RAD_MAX = 70.0f;
6880 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
6881
6882 ImGui::BeginGroup();
6883
6884 ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
6885
6886 const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
6887 const float offset_x = floorf(canvas_width * 0.5f);
6888 const float offset_y = floorf(RAD_MAX);
6889
6890 const ImVec2 p1 = ImGui::GetCursorScreenPos();
6891 draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
6892 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
6893
6894 /*
6895 const ImVec2 p2 = ImGui::GetCursorScreenPos();
6896 draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
6897 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
6898 */
6899
6900 ImGui::EndGroup();
6901 ImGui::SameLine();
6902 }
6903 ImGui::EndTooltip();
6904 }
6905 ImGui::SameLine();
6906 HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
6907
6908 ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
6909 ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha).");
6910 ImGui::PopItemWidth();
6911
6912 ImGui::EndTabItem();
6913 }
6914
6915 ImGui::EndTabBar();
6916 }
6917
6918 ImGui::PopItemWidth();
6919}
6920
6921//-----------------------------------------------------------------------------
6922// [SECTION] User Guide / ShowUserGuide()
6923//-----------------------------------------------------------------------------
6924
6925void ImGui::ShowUserGuide()
6926{
6927 ImGuiIO& io = ImGui::GetIO();
6928 ImGui::BulletText("Double-click on title bar to collapse window.");
6929 ImGui::BulletText(
6930 "Click and drag on lower corner to resize window\n"
6931 "(double-click to auto fit window to its contents).");
6932 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
6933 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
6934 ImGui::BulletText("CTRL+Tab to select a window.");
6935 if (io.FontAllowUserScaling)
6936 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
6937 ImGui::BulletText("While inputing text:\n");
6938 ImGui::Indent();
6939 ImGui::BulletText("CTRL+Left/Right to word jump.");
6940 ImGui::BulletText("CTRL+A or double-click to select all.");
6941 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
6942 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
6943 ImGui::BulletText("ESCAPE to revert.");
6944 ImGui::Unindent();
6945 ImGui::BulletText("With keyboard navigation enabled:");
6946 ImGui::Indent();
6947 ImGui::BulletText("Arrow keys to navigate.");
6948 ImGui::BulletText("Space to activate a widget.");
6949 ImGui::BulletText("Return to input text into a widget.");
6950 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
6951 ImGui::BulletText("Alt to jump to the menu layer of a window.");
6952 ImGui::Unindent();
6953}
6954
6955//-----------------------------------------------------------------------------
6956// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
6957//-----------------------------------------------------------------------------
6958// - ShowExampleAppMainMenuBar()
6959// - ShowExampleMenuFile()
6960//-----------------------------------------------------------------------------
6961
6962// Demonstrate creating a "main" fullscreen menu bar and populating it.
6963// Note the difference between BeginMainMenuBar() and BeginMenuBar():
6964// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
6965// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
6966static void ShowExampleAppMainMenuBar()
6967{
6968 if (ImGui::BeginMainMenuBar())
6969 {
6970 if (ImGui::BeginMenu("File"))
6971 {
6972 ShowExampleMenuFile();
6973 ImGui::EndMenu();
6974 }
6975 if (ImGui::BeginMenu("Edit"))
6976 {
6977 if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
6978 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
6979 ImGui::Separator();
6980 if (ImGui::MenuItem("Cut", "CTRL+X")) {}
6981 if (ImGui::MenuItem("Copy", "CTRL+C")) {}
6982 if (ImGui::MenuItem("Paste", "CTRL+V")) {}
6983 ImGui::EndMenu();
6984 }
6985 ImGui::EndMainMenuBar();
6986 }
6987}
6988
6989// Note that shortcuts are currently provided for display only
6990// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
6991static void ShowExampleMenuFile()
6992{
6993 IMGUI_DEMO_MARKER("Examples/Menu");
6994 ImGui::MenuItem("(demo menu)", NULL, false, false);
6995 if (ImGui::MenuItem("New")) {}
6996 if (ImGui::MenuItem("Open", "Ctrl+O")) {}
6997 if (ImGui::BeginMenu("Open Recent"))
6998 {
6999 ImGui::MenuItem("fish_hat.c");
7000 ImGui::MenuItem("fish_hat.inl");
7001 ImGui::MenuItem("fish_hat.h");
7002 if (ImGui::BeginMenu("More.."))
7003 {
7004 ImGui::MenuItem("Hello");
7005 ImGui::MenuItem("Sailor");
7006 if (ImGui::BeginMenu("Recurse.."))
7007 {
7008 ShowExampleMenuFile();
7009 ImGui::EndMenu();
7010 }
7011 ImGui::EndMenu();
7012 }
7013 ImGui::EndMenu();
7014 }
7015 if (ImGui::MenuItem("Save", "Ctrl+S")) {}
7016 if (ImGui::MenuItem("Save As..")) {}
7017
7018 ImGui::Separator();
7019 IMGUI_DEMO_MARKER("Examples/Menu/Options");
7020 if (ImGui::BeginMenu("Options"))
7021 {
7022 static bool enabled = true;
7023 ImGui::MenuItem("Enabled", "", &enabled);
7024 ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Border);
7025 for (int i = 0; i < 10; i++)
7026 ImGui::Text("Scrolling Text %d", i);
7027 ImGui::EndChild();
7028 static float f = 0.5f;
7029 static int n = 0;
7030 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
7031 ImGui::InputFloat("Input", &f, 0.1f);
7032 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
7033 ImGui::EndMenu();
7034 }
7035
7036 IMGUI_DEMO_MARKER("Examples/Menu/Colors");
7037 if (ImGui::BeginMenu("Colors"))
7038 {
7039 float sz = ImGui::GetTextLineHeight();
7040 for (int i = 0; i < ImGuiCol_COUNT; i++)
7041 {
7042 const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
7043 ImVec2 p = ImGui::GetCursorScreenPos();
7044 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
7045 ImGui::Dummy(ImVec2(sz, sz));
7046 ImGui::SameLine();
7047 ImGui::MenuItem(name);
7048 }
7049 ImGui::EndMenu();
7050 }
7051
7052 // Here we demonstrate appending again to the "Options" menu (which we already created above)
7053 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
7054 // In a real code-base using it would make senses to use this feature from very different code locations.
7055 if (ImGui::BeginMenu("Options")) // <-- Append!
7056 {
7057 IMGUI_DEMO_MARKER("Examples/Menu/Append to an existing menu");
7058 static bool b = true;
7059 ImGui::Checkbox("SomeOption", &b);
7060 ImGui::EndMenu();
7061 }
7062
7063 if (ImGui::BeginMenu("Disabled", false)) // Disabled
7064 {
7065 IM_ASSERT(0);
7066 }
7067 if (ImGui::MenuItem("Checked", NULL, true)) {}
7068 ImGui::Separator();
7069 if (ImGui::MenuItem("Quit", "Alt+F4")) {}
7070}
7071
7072//-----------------------------------------------------------------------------
7073// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
7074//-----------------------------------------------------------------------------
7075
7076// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
7077// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
7079{
7080 char InputBuf[256];
7081 ImVector<char*> Items;
7082 ImVector<const char*> Commands;
7083 ImVector<char*> History;
7084 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
7085 ImGuiTextFilter Filter;
7088
7090 {
7091 IMGUI_DEMO_MARKER("Examples/Console");
7092 ClearLog();
7093 memset(InputBuf, 0, sizeof(InputBuf));
7094 HistoryPos = -1;
7095
7096 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
7097 Commands.push_back("HELP");
7098 Commands.push_back("HISTORY");
7099 Commands.push_back("CLEAR");
7100 Commands.push_back("CLASSIFY");
7101 AutoScroll = true;
7102 ScrollToBottom = false;
7103 AddLog("Welcome to Dear ImGui!");
7104 }
7106 {
7107 ClearLog();
7108 for (int i = 0; i < History.Size; i++)
7109 ImGui::MemFree(History[i]);
7110 }
7111
7112 // Portable helpers
7113 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
7114 static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; }
7115 static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = ImGui::MemAlloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
7116 static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
7117
7119 {
7120 for (int i = 0; i < Items.Size; i++)
7121 ImGui::MemFree(Items[i]);
7122 Items.clear();
7123 }
7124
7125 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
7126 {
7127 // FIXME-OPT
7128 char buf[1024];
7129 va_list args;
7130 va_start(args, fmt);
7131 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
7132 buf[IM_ARRAYSIZE(buf)-1] = 0;
7133 va_end(args);
7134 Items.push_back(Strdup(buf));
7135 }
7136
7137 void Draw(const char* title, bool* p_open)
7138 {
7139 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
7140 if (!ImGui::Begin(title, p_open))
7141 {
7142 ImGui::End();
7143 return;
7144 }
7145
7146 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
7147 // So e.g. IsItemHovered() will return true when hovering the title bar.
7148 // Here we create a context menu only available from the title bar.
7149 if (ImGui::BeginPopupContextItem())
7150 {
7151 if (ImGui::MenuItem("Close Console"))
7152 *p_open = false;
7153 ImGui::EndPopup();
7154 }
7155
7156 ImGui::TextWrapped(
7157 "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
7158 "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
7159 ImGui::TextWrapped("Enter 'HELP' for help.");
7160
7161 // TODO: display items starting from the bottom
7162
7163 if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
7164 ImGui::SameLine();
7165 if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
7166 ImGui::SameLine();
7167 if (ImGui::SmallButton("Clear")) { ClearLog(); }
7168 ImGui::SameLine();
7169 bool copy_to_clipboard = ImGui::SmallButton("Copy");
7170 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
7171
7172 ImGui::Separator();
7173
7174 // Options menu
7175 if (ImGui::BeginPopup("Options"))
7176 {
7177 ImGui::Checkbox("Auto-scroll", &AutoScroll);
7178 ImGui::EndPopup();
7179 }
7180
7181 // Options, Filter
7182 if (ImGui::Button("Options"))
7183 ImGui::OpenPopup("Options");
7184 ImGui::SameLine();
7185 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
7186 ImGui::Separator();
7187
7188 // Reserve enough left-over height for 1 separator + 1 input text
7189 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
7190 if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
7191 {
7192 if (ImGui::BeginPopupContextWindow())
7193 {
7194 if (ImGui::Selectable("Clear")) ClearLog();
7195 ImGui::EndPopup();
7196 }
7197
7198 // Display every line as a separate entry so we can change their color or add custom widgets.
7199 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
7200 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
7201 // to only process visible items. The clipper will automatically measure the height of your first item and then
7202 // "seek" to display only items in the visible area.
7203 // To use the clipper we can replace your standard loop:
7204 // for (int i = 0; i < Items.Size; i++)
7205 // With:
7206 // ImGuiListClipper clipper;
7207 // clipper.Begin(Items.Size);
7208 // while (clipper.Step())
7209 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7210 // - That your items are evenly spaced (same height)
7211 // - That you have cheap random access to your elements (you can access them given their index,
7212 // without processing all the ones before)
7213 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
7214 // We would need random-access on the post-filtered list.
7215 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
7216 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
7217 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
7218 // to improve this example code!
7219 // If your items are of variable height:
7220 // - Split them into same height items would be simpler and facilitate random-seeking into your list.
7221 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
7222 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
7223 if (copy_to_clipboard)
7224 ImGui::LogToClipboard();
7225 for (const char* item : Items)
7226 {
7227 if (!Filter.PassFilter(item))
7228 continue;
7229
7230 // Normally you would store more information in your item than just a string.
7231 // (e.g. make Items[] an array of structure, store color/type etc.)
7232 ImVec4 color;
7233 bool has_color = false;
7234 if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
7235 else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
7236 if (has_color)
7237 ImGui::PushStyleColor(ImGuiCol_Text, color);
7239 if (has_color)
7240 ImGui::PopStyleColor();
7241 }
7242 if (copy_to_clipboard)
7243 ImGui::LogFinish();
7244
7245 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
7246 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
7247 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
7248 ImGui::SetScrollHereY(1.0f);
7249 ScrollToBottom = false;
7250
7251 ImGui::PopStyleVar();
7252 }
7253 ImGui::EndChild();
7254 ImGui::Separator();
7255
7256 // Command-line
7257 bool reclaim_focus = false;
7258 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_EscapeClearsAll | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
7259 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
7260 {
7261 char* s = InputBuf;
7262 Strtrim(s);
7263 if (s[0])
7264 ExecCommand(s);
7265 strcpy(s, "");
7266 reclaim_focus = true;
7267 }
7268
7269 // Auto-focus on window apparition
7270 ImGui::SetItemDefaultFocus();
7271 if (reclaim_focus)
7272 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
7273
7274 ImGui::End();
7275 }
7276
7277 void ExecCommand(const char* command_line)
7278 {
7279 AddLog("# %s\n", command_line);
7280
7281 // Insert into history. First find match and delete it so it can be pushed to the back.
7282 // This isn't trying to be smart or optimal.
7283 HistoryPos = -1;
7284 for (int i = History.Size - 1; i >= 0; i--)
7285 if (Stricmp(History[i], command_line) == 0)
7286 {
7287 ImGui::MemFree(History[i]);
7288 History.erase(History.begin() + i);
7289 break;
7290 }
7291 History.push_back(Strdup(command_line));
7292
7293 // Process command
7294 if (Stricmp(command_line, "CLEAR") == 0)
7295 {
7296 ClearLog();
7297 }
7298 else if (Stricmp(command_line, "HELP") == 0)
7299 {
7300 AddLog("Commands:");
7301 for (int i = 0; i < Commands.Size; i++)
7302 AddLog("- %s", Commands[i]);
7303 }
7304 else if (Stricmp(command_line, "HISTORY") == 0)
7305 {
7306 int first = History.Size - 10;
7307 for (int i = first > 0 ? first : 0; i < History.Size; i++)
7308 AddLog("%3d: %s\n", i, History[i]);
7309 }
7310 else
7311 {
7312 AddLog("Unknown command: '%s'\n", command_line);
7313 }
7314
7315 // On command input, we scroll to bottom even if AutoScroll==false
7316 ScrollToBottom = true;
7317 }
7318
7319 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
7320 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
7321 {
7322 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
7323 return console->TextEditCallback(data);
7324 }
7325
7326 int TextEditCallback(ImGuiInputTextCallbackData* data)
7327 {
7328 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
7329 switch (data->EventFlag)
7330 {
7331 case ImGuiInputTextFlags_CallbackCompletion:
7332 {
7333 // Example of TEXT COMPLETION
7334
7335 // Locate beginning of current word
7336 const char* word_end = data->Buf + data->CursorPos;
7337 const char* word_start = word_end;
7338 while (word_start > data->Buf)
7339 {
7340 const char c = word_start[-1];
7341 if (c == ' ' || c == '\t' || c == ',' || c == ';')
7342 break;
7343 word_start--;
7344 }
7345
7346 // Build a list of candidates
7347 ImVector<const char*> candidates;
7348 for (int i = 0; i < Commands.Size; i++)
7349 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
7350 candidates.push_back(Commands[i]);
7351
7352 if (candidates.Size == 0)
7353 {
7354 // No match
7355 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
7356 }
7357 else if (candidates.Size == 1)
7358 {
7359 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
7360 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
7361 data->InsertChars(data->CursorPos, candidates[0]);
7362 data->InsertChars(data->CursorPos, " ");
7363 }
7364 else
7365 {
7366 // Multiple matches. Complete as much as we can..
7367 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
7368 int match_len = (int)(word_end - word_start);
7369 for (;;)
7370 {
7371 int c = 0;
7372 bool all_candidates_matches = true;
7373 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
7374 if (i == 0)
7375 c = toupper(candidates[i][match_len]);
7376 else if (c == 0 || c != toupper(candidates[i][match_len]))
7377 all_candidates_matches = false;
7378 if (!all_candidates_matches)
7379 break;
7380 match_len++;
7381 }
7382
7383 if (match_len > 0)
7384 {
7385 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
7386 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
7387 }
7388
7389 // List matches
7390 AddLog("Possible matches:\n");
7391 for (int i = 0; i < candidates.Size; i++)
7392 AddLog("- %s\n", candidates[i]);
7393 }
7394
7395 break;
7396 }
7397 case ImGuiInputTextFlags_CallbackHistory:
7398 {
7399 // Example of HISTORY
7400 const int prev_history_pos = HistoryPos;
7401 if (data->EventKey == ImGuiKey_UpArrow)
7402 {
7403 if (HistoryPos == -1)
7404 HistoryPos = History.Size - 1;
7405 else if (HistoryPos > 0)
7406 HistoryPos--;
7407 }
7408 else if (data->EventKey == ImGuiKey_DownArrow)
7409 {
7410 if (HistoryPos != -1)
7411 if (++HistoryPos >= History.Size)
7412 HistoryPos = -1;
7413 }
7414
7415 // A better implementation would preserve the data on the current input line along with cursor position.
7416 if (prev_history_pos != HistoryPos)
7417 {
7418 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
7419 data->DeleteChars(0, data->BufTextLen);
7420 data->InsertChars(0, history_str);
7421 }
7422 }
7423 }
7424 return 0;
7425 }
7426};
7427
7428static void ShowExampleAppConsole(bool* p_open)
7429{
7430 static ExampleAppConsole console;
7431 console.Draw("Example: Console", p_open);
7432}
7433
7434//-----------------------------------------------------------------------------
7435// [SECTION] Example App: Debug Log / ShowExampleAppLog()
7436//-----------------------------------------------------------------------------
7437
7438// Usage:
7439// static ExampleAppLog my_log;
7440// my_log.AddLog("Hello %d world\n", 123);
7441// my_log.Draw("title");
7443{
7444 ImGuiTextBuffer Buf;
7445 ImGuiTextFilter Filter;
7446 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
7447 bool AutoScroll; // Keep scrolling if already at the bottom.
7448
7450 {
7451 AutoScroll = true;
7452 Clear();
7453 }
7454
7455 void Clear()
7456 {
7457 Buf.clear();
7458 LineOffsets.clear();
7459 LineOffsets.push_back(0);
7460 }
7461
7462 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
7463 {
7464 int old_size = Buf.size();
7465 va_list args;
7466 va_start(args, fmt);
7467 Buf.appendfv(fmt, args);
7468 va_end(args);
7469 for (int new_size = Buf.size(); old_size < new_size; old_size++)
7470 if (Buf[old_size] == '\n')
7471 LineOffsets.push_back(old_size + 1);
7472 }
7473
7474 void Draw(const char* title, bool* p_open = NULL)
7475 {
7476 if (!ImGui::Begin(title, p_open))
7477 {
7478 ImGui::End();
7479 return;
7480 }
7481
7482 // Options menu
7483 if (ImGui::BeginPopup("Options"))
7484 {
7485 ImGui::Checkbox("Auto-scroll", &AutoScroll);
7486 ImGui::EndPopup();
7487 }
7488
7489 // Main window
7490 if (ImGui::Button("Options"))
7491 ImGui::OpenPopup("Options");
7492 ImGui::SameLine();
7493 bool clear = ImGui::Button("Clear");
7494 ImGui::SameLine();
7495 bool copy = ImGui::Button("Copy");
7496 ImGui::SameLine();
7497 Filter.Draw("Filter", -100.0f);
7498
7499 ImGui::Separator();
7500
7501 if (ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar))
7502 {
7503 if (clear)
7504 Clear();
7505 if (copy)
7506 ImGui::LogToClipboard();
7507
7508 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
7509 const char* buf = Buf.begin();
7510 const char* buf_end = Buf.end();
7511 if (Filter.IsActive())
7512 {
7513 // In this example we don't use the clipper when Filter is enabled.
7514 // This is because we don't have random access to the result of our filter.
7515 // A real application processing logs with ten of thousands of entries may want to store the result of
7516 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
7517 for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
7518 {
7519 const char* line_start = buf + LineOffsets[line_no];
7520 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
7521 if (Filter.PassFilter(line_start, line_end))
7522 ImGui::TextUnformatted(line_start, line_end);
7523 }
7524 }
7525 else
7526 {
7527 // The simplest and easy way to display the entire buffer:
7528 // ImGui::TextUnformatted(buf_begin, buf_end);
7529 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
7530 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
7531 // within the visible area.
7532 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
7533 // on your side is recommended. Using ImGuiListClipper requires
7534 // - A) random access into your data
7535 // - B) items all being the same height,
7536 // both of which we can handle since we have an array pointing to the beginning of each line of text.
7537 // When using the filter (in the block of code above) we don't have random access into the data to display
7538 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
7539 // it possible (and would be recommended if you want to search through tens of thousands of entries).
7540 ImGuiListClipper clipper;
7541 clipper.Begin(LineOffsets.Size);
7542 while (clipper.Step())
7543 {
7544 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
7545 {
7546 const char* line_start = buf + LineOffsets[line_no];
7547 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
7548 ImGui::TextUnformatted(line_start, line_end);
7549 }
7550 }
7551 clipper.End();
7552 }
7553 ImGui::PopStyleVar();
7554
7555 // Keep up at the bottom of the scroll region if we were already at the bottom at the beginning of the frame.
7556 // Using a scrollbar or mouse-wheel will take away from the bottom edge.
7557 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
7558 ImGui::SetScrollHereY(1.0f);
7559 }
7560 ImGui::EndChild();
7561 ImGui::End();
7562 }
7563};
7564
7565// Demonstrate creating a simple log window with basic filtering.
7566static void ShowExampleAppLog(bool* p_open)
7567{
7568 static ExampleAppLog log;
7569
7570 // For the demo: add a debug button _BEFORE_ the normal log window contents
7571 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
7572 // Most of the contents of the window will be added by the log.Draw() call.
7573 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
7574 ImGui::Begin("Example: Log", p_open);
7575 IMGUI_DEMO_MARKER("Examples/Log");
7576 if (ImGui::SmallButton("[Debug] Add 5 entries"))
7577 {
7578 static int counter = 0;
7579 const char* categories[3] = { "info", "warn", "error" };
7580 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
7581 for (int n = 0; n < 5; n++)
7582 {
7583 const char* category = categories[counter % IM_ARRAYSIZE(categories)];
7584 const char* word = words[counter % IM_ARRAYSIZE(words)];
7585 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
7586 ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
7587 counter++;
7588 }
7589 }
7590 ImGui::End();
7591
7592 // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
7593 log.Draw("Example: Log", p_open);
7594}
7595
7596//-----------------------------------------------------------------------------
7597// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
7598//-----------------------------------------------------------------------------
7599
7600// Demonstrate create a window with multiple child windows.
7601static void ShowExampleAppLayout(bool* p_open)
7602{
7603 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
7604 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
7605 {
7606 IMGUI_DEMO_MARKER("Examples/Simple layout");
7607 if (ImGui::BeginMenuBar())
7608 {
7609 if (ImGui::BeginMenu("File"))
7610 {
7611 if (ImGui::MenuItem("Close", "Ctrl+W")) { *p_open = false; }
7612 ImGui::EndMenu();
7613 }
7614 ImGui::EndMenuBar();
7615 }
7616
7617 // Left
7618 static int selected = 0;
7619 {
7620 ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX);
7621 for (int i = 0; i < 100; i++)
7622 {
7623 // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
7624 char label[128];
7625 sprintf(label, "MyObject %d", i);
7626 if (ImGui::Selectable(label, selected == i))
7627 selected = i;
7628 }
7629 ImGui::EndChild();
7630 }
7631 ImGui::SameLine();
7632
7633 // Right
7634 {
7635 ImGui::BeginGroup();
7636 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
7637 ImGui::Text("MyObject: %d", selected);
7638 ImGui::Separator();
7639 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
7640 {
7641 if (ImGui::BeginTabItem("Description"))
7642 {
7643 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
7644 ImGui::EndTabItem();
7645 }
7646 if (ImGui::BeginTabItem("Details"))
7647 {
7648 ImGui::Text("ID: 0123456789");
7649 ImGui::EndTabItem();
7650 }
7651 ImGui::EndTabBar();
7652 }
7653 ImGui::EndChild();
7654 if (ImGui::Button("Revert")) {}
7655 ImGui::SameLine();
7656 if (ImGui::Button("Save")) {}
7657 ImGui::EndGroup();
7658 }
7659 }
7660 ImGui::End();
7661}
7662
7663//-----------------------------------------------------------------------------
7664// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
7665//-----------------------------------------------------------------------------
7666
7667static void ShowPlaceholderObject(const char* prefix, int uid)
7668{
7669 // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
7670 ImGui::PushID(uid);
7671
7672 // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high.
7673 ImGui::TableNextRow();
7674 ImGui::TableSetColumnIndex(0);
7675 ImGui::AlignTextToFramePadding();
7676 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
7677 ImGui::TableSetColumnIndex(1);
7678 ImGui::Text("my sailor is rich");
7679
7680 if (node_open)
7681 {
7682 static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f };
7683 for (int i = 0; i < 8; i++)
7684 {
7685 ImGui::PushID(i); // Use field index as identifier.
7686 if (i < 2)
7687 {
7688 ShowPlaceholderObject("Child", 424242);
7689 }
7690 else
7691 {
7692 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well)
7693 ImGui::TableNextRow();
7694 ImGui::TableSetColumnIndex(0);
7695 ImGui::AlignTextToFramePadding();
7696 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet;
7697 ImGui::TreeNodeEx("Field", flags, "Field_%d", i);
7698
7699 ImGui::TableSetColumnIndex(1);
7700 ImGui::SetNextItemWidth(-FLT_MIN);
7701 if (i >= 5)
7702 ImGui::InputFloat("##value", &placeholder_members[i], 1.0f);
7703 else
7704 ImGui::DragFloat("##value", &placeholder_members[i], 0.01f);
7705 ImGui::NextColumn();
7706 }
7707 ImGui::PopID();
7708 }
7709 ImGui::TreePop();
7710 }
7711 ImGui::PopID();
7712}
7713
7714// Demonstrate create a simple property editor.
7715// This demo is a bit lackluster nowadays, would be nice to improve.
7716static void ShowExampleAppPropertyEditor(bool* p_open)
7717{
7718 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
7719 if (!ImGui::Begin("Example: Property editor", p_open))
7720 {
7721 ImGui::End();
7722 return;
7723 }
7724
7725 IMGUI_DEMO_MARKER("Examples/Property Editor");
7726 HelpMarker(
7727 "This example shows how you may implement a property editor using two columns.\n"
7728 "All objects/fields data are dummies here.\n");
7729
7730 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
7731 if (ImGui::BeginTable("##split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
7732 {
7733 ImGui::TableSetupScrollFreeze(0, 1);
7734 ImGui::TableSetupColumn("Object");
7735 ImGui::TableSetupColumn("Contents");
7736 ImGui::TableHeadersRow();
7737
7738 // Iterate placeholder objects (all the same data)
7739 for (int obj_i = 0; obj_i < 4; obj_i++)
7740 ShowPlaceholderObject("Object", obj_i);
7741
7742 ImGui::EndTable();
7743 }
7744 ImGui::PopStyleVar();
7745 ImGui::End();
7746}
7747
7748//-----------------------------------------------------------------------------
7749// [SECTION] Example App: Long Text / ShowExampleAppLongText()
7750//-----------------------------------------------------------------------------
7751
7752// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
7753static void ShowExampleAppLongText(bool* p_open)
7754{
7755 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
7756 if (!ImGui::Begin("Example: Long text display", p_open))
7757 {
7758 ImGui::End();
7759 return;
7760 }
7761 IMGUI_DEMO_MARKER("Examples/Long text display");
7762
7763 static int test_type = 0;
7764 static ImGuiTextBuffer log;
7765 static int lines = 0;
7766 ImGui::Text("Printing unusually long amount of text.");
7767 ImGui::Combo("Test type", &test_type,
7768 "Single call to TextUnformatted()\0"
7769 "Multiple calls to Text(), clipped\0"
7770 "Multiple calls to Text(), not clipped (slow)\0");
7771 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
7772 if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
7773 ImGui::SameLine();
7774 if (ImGui::Button("Add 1000 lines"))
7775 {
7776 for (int i = 0; i < 1000; i++)
7777 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
7778 lines += 1000;
7779 }
7780 ImGui::BeginChild("Log");
7781 switch (test_type)
7782 {
7783 case 0:
7784 // Single call to TextUnformatted() with a big buffer
7785 ImGui::TextUnformatted(log.begin(), log.end());
7786 break;
7787 case 1:
7788 {
7789 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
7790 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
7791 ImGuiListClipper clipper;
7792 clipper.Begin(lines);
7793 while (clipper.Step())
7794 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
7795 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
7796 ImGui::PopStyleVar();
7797 break;
7798 }
7799 case 2:
7800 // Multiple calls to Text(), not clipped (slow)
7801 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
7802 for (int i = 0; i < lines; i++)
7803 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
7804 ImGui::PopStyleVar();
7805 break;
7806 }
7807 ImGui::EndChild();
7808 ImGui::End();
7809}
7810
7811//-----------------------------------------------------------------------------
7812// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
7813//-----------------------------------------------------------------------------
7814
7815// Demonstrate creating a window which gets auto-resized according to its content.
7816static void ShowExampleAppAutoResize(bool* p_open)
7817{
7818 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
7819 {
7820 ImGui::End();
7821 return;
7822 }
7823 IMGUI_DEMO_MARKER("Examples/Auto-resizing window");
7824
7825 static int lines = 10;
7827 "Window will resize every-frame to the size of its content.\n"
7828 "Note that you probably don't want to query the window size to\n"
7829 "output your content because that would create a feedback loop.");
7830 ImGui::SliderInt("Number of lines", &lines, 1, 20);
7831 for (int i = 0; i < lines; i++)
7832 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
7833 ImGui::End();
7834}
7835
7836//-----------------------------------------------------------------------------
7837// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
7838//-----------------------------------------------------------------------------
7839
7840// Demonstrate creating a window with custom resize constraints.
7841// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
7842static void ShowExampleAppConstrainedResize(bool* p_open)
7843{
7844 struct CustomConstraints
7845 {
7846 // Helper functions to demonstrate programmatic constraints
7847 // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
7848 // FIXME: None of the three demos works consistently when resizing from borders.
7849 static void AspectRatio(ImGuiSizeCallbackData* data)
7850 {
7851 float aspect_ratio = *(float*)data->UserData;
7852 data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio);
7853 }
7854 static void Square(ImGuiSizeCallbackData* data)
7855 {
7856 data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y);
7857 }
7858 static void Step(ImGuiSizeCallbackData* data)
7859 {
7860 float step = *(float*)data->UserData;
7861 data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
7862 }
7863 };
7864
7865 const char* test_desc[] =
7866 {
7867 "Between 100x100 and 500x500",
7868 "At least 100x100",
7869 "Resize vertical + lock current width",
7870 "Resize horizontal + lock current height",
7871 "Width Between 400 and 500",
7872 "Height at least 400",
7873 "Custom: Aspect Ratio 16:9",
7874 "Custom: Always Square",
7875 "Custom: Fixed Steps (100)",
7876 };
7877
7878 // Options
7879 static bool auto_resize = false;
7880 static bool window_padding = true;
7881 static int type = 6; // Aspect Ratio
7882 static int display_lines = 10;
7883
7884 // Submit constraint
7885 float aspect_ratio = 16.0f / 9.0f;
7886 float fixed_step = 100.0f;
7887 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500
7888 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
7889 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Resize vertical + lock current width
7890 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Resize horizontal + lock current height
7891 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500
7892 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 500), ImVec2(-1, FLT_MAX)); // Height at least 400
7893 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio
7894 if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
7895 if (type == 8) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step
7896
7897 // Submit window
7898 if (!window_padding)
7899 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
7900 const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
7901 const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
7902 if (!window_padding)
7903 ImGui::PopStyleVar();
7904 if (window_open)
7905 {
7906 IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
7907 if (ImGui::GetIO().KeyShift)
7908 {
7909 // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture.
7910 ImVec2 avail_size = ImGui::GetContentRegionAvail();
7911 ImVec2 pos = ImGui::GetCursorScreenPos();
7912 ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
7913 ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
7914 ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
7915 }
7916 else
7917 {
7918 ImGui::Text("(Hold SHIFT to display a dummy viewport)");
7919 if (ImGui::IsWindowDocked())
7920 ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
7921 if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
7922 if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
7923 if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
7924 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
7925 ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
7926 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
7927 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
7928 ImGui::Checkbox("Auto-resize", &auto_resize);
7929 ImGui::Checkbox("Window padding", &window_padding);
7930 for (int i = 0; i < display_lines; i++)
7931 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
7932 }
7933 }
7934 ImGui::End();
7935}
7936
7937//-----------------------------------------------------------------------------
7938// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
7939//-----------------------------------------------------------------------------
7940
7941// Demonstrate creating a simple static window with no decoration
7942// + a context-menu to choose which corner of the screen to use.
7943static void ShowExampleAppSimpleOverlay(bool* p_open)
7944{
7945 static int location = 0;
7946 ImGuiIO& io = ImGui::GetIO();
7947 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
7948 if (location >= 0)
7949 {
7950 const float PAD = 10.0f;
7951 const ImGuiViewport* viewport = ImGui::GetMainViewport();
7952 ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
7953 ImVec2 work_size = viewport->WorkSize;
7954 ImVec2 window_pos, window_pos_pivot;
7955 window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
7956 window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
7957 window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
7958 window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
7959 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
7960 ImGui::SetNextWindowViewport(viewport->ID);
7961 window_flags |= ImGuiWindowFlags_NoMove;
7962 }
7963 else if (location == -2)
7964 {
7965 // Center window
7966 ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
7967 window_flags |= ImGuiWindowFlags_NoMove;
7968 }
7969 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
7970 if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
7971 {
7972 IMGUI_DEMO_MARKER("Examples/Simple Overlay");
7973 ImGui::Text("Simple overlay\n" "(right-click to change position)");
7974 ImGui::Separator();
7975 if (ImGui::IsMousePosValid())
7976 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
7977 else
7978 ImGui::Text("Mouse Position: <invalid>");
7979 if (ImGui::BeginPopupContextWindow())
7980 {
7981 if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1;
7982 if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2;
7983 if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0;
7984 if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1;
7985 if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2;
7986 if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
7987 if (p_open && ImGui::MenuItem("Close")) *p_open = false;
7988 ImGui::EndPopup();
7989 }
7990 }
7991 ImGui::End();
7992}
7993
7994//-----------------------------------------------------------------------------
7995// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
7996//-----------------------------------------------------------------------------
7997
7998// Demonstrate creating a window covering the entire screen/viewport
7999static void ShowExampleAppFullscreen(bool* p_open)
8000{
8001 static bool use_work_area = true;
8002 static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
8003
8004 // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
8005 // Based on your use case you may want one or the other.
8006 const ImGuiViewport* viewport = ImGui::GetMainViewport();
8007 ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
8008 ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
8009
8010 if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
8011 {
8012 ImGui::Checkbox("Use work area instead of main area", &use_work_area);
8013 ImGui::SameLine();
8014 HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.");
8015
8016 ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
8017 ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
8018 ImGui::Indent();
8019 ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
8020 ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
8021 ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
8022 ImGui::Unindent();
8023
8024 if (p_open && ImGui::Button("Close this window"))
8025 *p_open = false;
8026 }
8027 ImGui::End();
8028}
8029
8030//-----------------------------------------------------------------------------
8031// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
8032//-----------------------------------------------------------------------------
8033
8034// Demonstrate the use of "##" and "###" in identifiers to manipulate ID generation.
8035// This applies to all regular items as well.
8036// Read FAQ section "How can I have multiple widgets with the same label?" for details.
8037static void ShowExampleAppWindowTitles(bool*)
8038{
8039 const ImGuiViewport* viewport = ImGui::GetMainViewport();
8040 const ImVec2 base_pos = viewport->Pos;
8041
8042 // By default, Windows are uniquely identified by their title.
8043 // You can use the "##" and "###" markers to manipulate the display/ID.
8044
8045 // Using "##" to display same title but have unique identifier.
8046 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
8047 ImGui::Begin("Same title as another window##1");
8048 IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
8049 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
8050 ImGui::End();
8051
8052 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
8053 ImGui::Begin("Same title as another window##2");
8054 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
8055 ImGui::End();
8056
8057 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
8058 char buf[128];
8059 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
8060 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
8061 ImGui::Begin(buf);
8062 ImGui::Text("This window has a changing title.");
8063 ImGui::End();
8064}
8065
8066//-----------------------------------------------------------------------------
8067// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
8068//-----------------------------------------------------------------------------
8069
8070// Add a |_| looking shape
8071static void PathConcaveShape(ImDrawList* draw_list, float x, float y, float sz)
8072{
8073 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 } };
8074 for (const ImVec2& p : pos_norms)
8075 draw_list->PathLineTo(ImVec2(x + 0.5f + (int)(sz * p.x), y + 0.5f + (int)(sz * p.y)));
8076}
8077
8078// Demonstrate using the low-level ImDrawList to draw custom shapes.
8079static void ShowExampleAppCustomRendering(bool* p_open)
8080{
8081 if (!ImGui::Begin("Example: Custom rendering", p_open))
8082 {
8083 ImGui::End();
8084 return;
8085 }
8086 IMGUI_DEMO_MARKER("Examples/Custom Rendering");
8087
8088 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
8089 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
8090 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
8091 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
8092
8093 if (ImGui::BeginTabBar("##TabBar"))
8094 {
8095 if (ImGui::BeginTabItem("Primitives"))
8096 {
8097 ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
8098 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8099
8100 // Draw gradients
8101 // (note that those are currently exacerbating our sRGB/Linear issues)
8102 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
8103 ImGui::Text("Gradients");
8104 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
8105 {
8106 ImVec2 p0 = ImGui::GetCursorScreenPos();
8107 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
8108 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
8109 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
8110 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
8111 ImGui::InvisibleButton("##gradient1", gradient_size);
8112 }
8113 {
8114 ImVec2 p0 = ImGui::GetCursorScreenPos();
8115 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
8116 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
8117 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
8118 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
8119 ImGui::InvisibleButton("##gradient2", gradient_size);
8120 }
8121
8122 // Draw a bunch of primitives
8123 ImGui::Text("All primitives");
8124 static float sz = 36.0f;
8125 static float thickness = 3.0f;
8126 static int ngon_sides = 6;
8127 static bool circle_segments_override = false;
8128 static int circle_segments_override_v = 12;
8129 static bool curve_segments_override = false;
8130 static int curve_segments_override_v = 8;
8131 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
8132 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
8133 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
8134 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
8135 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
8136 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
8137 circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
8138 ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
8139 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
8140 curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
8141 ImGui::ColorEdit4("Color", &colf.x);
8142
8143 const ImVec2 p = ImGui::GetCursorScreenPos();
8144 const ImU32 col = ImColor(colf);
8145 const float spacing = 10.0f;
8146 const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
8147 const float rounding = sz / 5.0f;
8148 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
8149 const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
8150 const ImVec2 cp3[3] = { ImVec2(0.0f, sz * 0.6f), ImVec2(sz * 0.5f, -sz * 0.4f), ImVec2(sz, sz) }; // Control points for curves
8151 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) };
8152
8153 float x = p.x + 4.0f;
8154 float y = p.y + 4.0f;
8155 for (int n = 0; n < 2; n++)
8156 {
8157 // First line uses a thickness of 1.0f, second line uses the configurable thickness
8158 float th = (n == 0) ? 1.0f : thickness;
8159 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
8160 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
8161 draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, sz*0.3f, col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse
8162 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
8163 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
8164 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners
8165 draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle
8166 //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
8167 PathConcaveShape(draw_list, x, y, sz); draw_list->PathStroke(col, ImDrawFlags_Closed, th); x += sz + spacing; // Concave Shape
8168 //draw_list->AddPolyline(concave_shape, IM_ARRAYSIZE(concave_shape), col, ImDrawFlags_Closed, th);
8169 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
8170 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
8171 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
8172
8173 // Path
8174 draw_list->PathArcTo(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, 3.141592f, 3.141592f * -0.5f);
8175 draw_list->PathStroke(col, ImDrawFlags_None, th);
8176 x += sz + spacing;
8177
8178 // Quadratic Bezier Curve (3 control points)
8179 draw_list->AddBezierQuadratic(ImVec2(x + cp3[0].x, y + cp3[0].y), ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), col, th, curve_segments);
8180 x += sz + spacing;
8181
8182 // Cubic Bezier Curve (4 control points)
8183 draw_list->AddBezierCubic(ImVec2(x + cp4[0].x, y + cp4[0].y), ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), col, th, curve_segments);
8184
8185 x = p.x + 4;
8186 y += sz + spacing;
8187 }
8188
8189 // Filled shapes
8190 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, ngon_sides); x += sz + spacing; // N-gon
8191 draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col, circle_segments); x += sz + spacing; // Circle
8192 draw_list->AddEllipseFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, sz * 0.3f, col, -0.3f, circle_segments); x += sz + spacing;// Ellipse
8193 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
8194 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners
8195 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners
8196 draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle
8197 //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
8198 PathConcaveShape(draw_list, x, y, sz); draw_list->PathFillConcave(col); x += sz + spacing; // Concave shape
8199 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness)
8200 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness)
8201 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
8202
8203 // Path
8204 draw_list->PathArcTo(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, 3.141592f * -0.5f, 3.141592f);
8205 draw_list->PathFillConvex(col);
8206 x += sz + spacing;
8207
8208 // Quadratic Bezier Curve (3 control points)
8209 draw_list->PathLineTo(ImVec2(x + cp3[0].x, y + cp3[0].y));
8210 draw_list->PathBezierQuadraticCurveTo(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), curve_segments);
8211 draw_list->PathFillConvex(col);
8212 x += sz + spacing;
8213
8214 draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255));
8215 x += sz + spacing;
8216
8217 ImGui::Dummy(ImVec2((sz + spacing) * 13.2f, (sz + spacing) * 3.0f));
8218 ImGui::PopItemWidth();
8219 ImGui::EndTabItem();
8220 }
8221
8222 if (ImGui::BeginTabItem("Canvas"))
8223 {
8224 static ImVector<ImVec2> points;
8225 static ImVec2 scrolling(0.0f, 0.0f);
8226 static bool opt_enable_grid = true;
8227 static bool opt_enable_context_menu = true;
8228 static bool adding_line = false;
8229
8230 ImGui::Checkbox("Enable grid", &opt_enable_grid);
8231 ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
8232 ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
8233
8234 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
8235 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
8236 // To use a child window instead we could use, e.g:
8237 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
8238 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
8239 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove);
8240 // ImGui::PopStyleColor();
8241 // ImGui::PopStyleVar();
8242 // [...]
8243 // ImGui::EndChild();
8244
8245 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
8246 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
8247 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
8248 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
8249 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
8250 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
8251
8252 // Draw border and background color
8253 ImGuiIO& io = ImGui::GetIO();
8254 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8255 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
8256 draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
8257
8258 // This will catch our interactions
8259 ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
8260 const bool is_hovered = ImGui::IsItemHovered(); // Hovered
8261 const bool is_active = ImGui::IsItemActive(); // Held
8262 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
8263 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
8264
8265 // Add first and second point
8266 if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
8267 {
8268 points.push_back(mouse_pos_in_canvas);
8269 points.push_back(mouse_pos_in_canvas);
8270 adding_line = true;
8271 }
8272 if (adding_line)
8273 {
8274 points.back() = mouse_pos_in_canvas;
8275 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
8276 adding_line = false;
8277 }
8278
8279 // Pan (we use a zero mouse threshold when there's no context menu)
8280 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
8281 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
8282 if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
8283 {
8284 scrolling.x += io.MouseDelta.x;
8285 scrolling.y += io.MouseDelta.y;
8286 }
8287
8288 // Context menu (under default mouse threshold)
8289 ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
8290 if (opt_enable_context_menu && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
8291 ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
8292 if (ImGui::BeginPopup("context"))
8293 {
8294 if (adding_line)
8295 points.resize(points.size() - 2);
8296 adding_line = false;
8297 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
8298 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
8299 ImGui::EndPopup();
8300 }
8301
8302 // Draw grid + all lines in the canvas
8303 draw_list->PushClipRect(canvas_p0, canvas_p1, true);
8304 if (opt_enable_grid)
8305 {
8306 const float GRID_STEP = 64.0f;
8307 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
8308 draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
8309 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
8310 draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
8311 }
8312 for (int n = 0; n < points.Size; n += 2)
8313 draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
8314 draw_list->PopClipRect();
8315
8316 ImGui::EndTabItem();
8317 }
8318
8319 if (ImGui::BeginTabItem("BG/FG draw lists"))
8320 {
8321 static bool draw_bg = true;
8322 static bool draw_fg = true;
8323 ImGui::Checkbox("Draw in Background draw list", &draw_bg);
8324 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
8325 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
8326 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
8327 ImVec2 window_pos = ImGui::GetWindowPos();
8328 ImVec2 window_size = ImGui::GetWindowSize();
8329 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
8330 if (draw_bg)
8331 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
8332 if (draw_fg)
8333 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
8334 ImGui::EndTabItem();
8335 }
8336
8337 // Demonstrate out-of-order rendering via channels splitting
8338 // We use functions in ImDrawList as each draw list contains a convenience splitter,
8339 // but you can also instantiate your own ImDrawListSplitter if you need to nest them.
8340 if (ImGui::BeginTabItem("Draw Channels"))
8341 {
8342 ImDrawList* draw_list = ImGui::GetWindowDrawList();
8343 {
8344 ImGui::Text("Blue shape is drawn first: appears in back");
8345 ImGui::Text("Red shape is drawn after: appears in front");
8346 ImVec2 p0 = ImGui::GetCursorScreenPos();
8347 draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
8348 draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
8349 ImGui::Dummy(ImVec2(75, 75));
8350 }
8351 ImGui::Separator();
8352 {
8353 ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
8354 ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
8355 ImVec2 p1 = ImGui::GetCursorScreenPos();
8356
8357 // Create 2 channels and draw a Blue shape THEN a Red shape.
8358 // You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
8359 draw_list->ChannelsSplit(2);
8360 draw_list->ChannelsSetCurrent(1);
8361 draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
8362 draw_list->ChannelsSetCurrent(0);
8363 draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
8364
8365 // Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
8366 // This works by copying draw indices only (vertices are not copied).
8367 draw_list->ChannelsMerge();
8368 ImGui::Dummy(ImVec2(75, 75));
8369 ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
8370 }
8371 ImGui::EndTabItem();
8372 }
8373
8374 ImGui::EndTabBar();
8375 }
8376
8377 ImGui::End();
8378}
8379
8380//-----------------------------------------------------------------------------
8381// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
8382//-----------------------------------------------------------------------------
8383
8384// Demonstrate using DockSpace() to create an explicit docking node within an existing window.
8385// Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking!
8386// - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
8387// - Drag from window menu button (upper-left button) to undock an entire node (all windows).
8388// - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking.
8389// About dockspaces:
8390// - Use DockSpace() to create an explicit dock node _within_ an existing window.
8391// - Use DockSpaceOverViewport() to create an explicit dock node covering the screen or a specific viewport.
8392// This is often used with ImGuiDockNodeFlags_PassthruCentralNode.
8393// - Important: Dockspaces need to be submitted _before_ any window they can host. Submit it early in your frame! (*)
8394// - Important: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
8395// e.g. if you have multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
8396// (*) because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node,
8397// because that window is submitted as part of the part of the NewFrame() call. An easy workaround is that you can create
8398// your own implicit "Debug##2" window after calling DockSpace() and leave it in the window stack for anyone to use.
8399void ShowExampleAppDockSpace(bool* p_open)
8400{
8401 // READ THIS !!!
8402 // TL;DR; this demo is more complicated than what most users you would normally use.
8403 // If we remove all options we are showcasing, this demo would become:
8404 // void ShowExampleAppDockSpace()
8405 // {
8406 // ImGui::DockSpaceOverViewport(ImGui::GetMainViewport());
8407 // }
8408 // In most cases you should be able to just call DockSpaceOverViewport() and ignore all the code below!
8409 // In this specific demo, we are not using DockSpaceOverViewport() because:
8410 // - (1) we allow the host window to be floating/moveable instead of filling the viewport (when opt_fullscreen == false)
8411 // - (2) we allow the host window to have padding (when opt_padding == true)
8412 // - (3) we expose many flags and need a way to have them visible.
8413 // - (4) we have a local menu bar in the host window (vs. you could use BeginMainMenuBar() + DockSpaceOverViewport()
8414 // in your code, but we don't here because we allow the window to be floating)
8415
8416 static bool opt_fullscreen = true;
8417 static bool opt_padding = false;
8418 static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
8419
8420 // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
8421 // because it would be confusing to have two docking targets within each others.
8422 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
8423 if (opt_fullscreen)
8424 {
8425 const ImGuiViewport* viewport = ImGui::GetMainViewport();
8426 ImGui::SetNextWindowPos(viewport->WorkPos);
8427 ImGui::SetNextWindowSize(viewport->WorkSize);
8428 ImGui::SetNextWindowViewport(viewport->ID);
8429 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
8430 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
8431 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
8432 window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
8433 }
8434 else
8435 {
8436 dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
8437 }
8438
8439 // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
8440 // and handle the pass-thru hole, so we ask Begin() to not render a background.
8441 if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
8442 window_flags |= ImGuiWindowFlags_NoBackground;
8443
8444 // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
8445 // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
8446 // all active windows docked into it will lose their parent and become undocked.
8447 // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
8448 // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
8449 if (!opt_padding)
8450 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
8451 ImGui::Begin("DockSpace Demo", p_open, window_flags);
8452 if (!opt_padding)
8453 ImGui::PopStyleVar();
8454
8455 if (opt_fullscreen)
8456 ImGui::PopStyleVar(2);
8457
8458 // Submit the DockSpace
8459 ImGuiIO& io = ImGui::GetIO();
8460 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
8461 {
8462 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
8463 ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
8464 }
8465 else
8466 {
8467 ShowDockingDisabledMessage();
8468 }
8469
8470 if (ImGui::BeginMenuBar())
8471 {
8472 if (ImGui::BeginMenu("Options"))
8473 {
8474 // Disabling fullscreen would allow the window to be moved to the front of other windows,
8475 // which we can't undo at the moment without finer window depth/z control.
8476 ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
8477 ImGui::MenuItem("Padding", NULL, &opt_padding);
8478 ImGui::Separator();
8479
8480 if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode; }
8481 if (ImGui::MenuItem("Flag: NoDockingSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit; }
8482 if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking; }
8483 if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
8484 if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
8485 if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
8486 ImGui::Separator();
8487
8488 if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
8489 *p_open = false;
8490 ImGui::EndMenu();
8491 }
8492 HelpMarker(
8493 "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
8494 "- Drag from window title bar or their tab to dock/undock." "\n"
8495 "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
8496 "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
8497 "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)" "\n"
8498 "This demo app has nothing to do with enabling docking!" "\n\n"
8499 "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window." "\n\n"
8500 "Read comments in ShowExampleAppDockSpace() for more details.");
8501
8502 ImGui::EndMenuBar();
8503 }
8504
8505 ImGui::End();
8506}
8507
8508//-----------------------------------------------------------------------------
8509// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
8510//-----------------------------------------------------------------------------
8511
8512// Simplified structure to mimic a Document model
8514{
8515 const char* Name; // Document title
8516 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
8517 bool OpenPrev; // Copy of Open from last update.
8518 bool Dirty; // Set when the document has been modified
8519 bool WantClose; // Set when the document
8520 ImVec4 Color; // An arbitrary variable associated to the document
8521
8522 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
8523 {
8524 Name = name;
8525 Open = OpenPrev = open;
8526 Dirty = false;
8527 WantClose = false;
8528 Color = color;
8529 }
8530 void DoOpen() { Open = true; }
8531 void DoQueueClose() { WantClose = true; }
8532 void DoForceClose() { Open = false; Dirty = false; }
8533 void DoSave() { Dirty = false; }
8534
8535 // Display placeholder contents for the Document
8536 static void DisplayContents(MyDocument* doc)
8537 {
8538 ImGui::PushID(doc);
8539 ImGui::Text("Document \"%s\"", doc->Name);
8540 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
8541 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
8542 ImGui::PopStyleColor();
8543 if (ImGui::Button("Modify", ImVec2(100, 0)))
8544 doc->Dirty = true;
8545 ImGui::SameLine();
8546 if (ImGui::Button("Save", ImVec2(100, 0)))
8547 doc->DoSave();
8548 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
8549 ImGui::PopID();
8550 }
8551
8552 // Display context menu for the Document
8554 {
8555 if (!ImGui::BeginPopupContextItem())
8556 return;
8557
8558 char buf[256];
8559 sprintf(buf, "Save %s", doc->Name);
8560 if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open))
8561 doc->DoSave();
8562 if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open))
8563 doc->DoQueueClose();
8564 ImGui::EndPopup();
8565 }
8566};
8567
8569{
8570 ImVector<MyDocument> Documents;
8571
8573 {
8574 Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
8575 Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
8576 Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
8577 Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
8578 Documents.push_back(MyDocument("A Rather Long Title", false));
8579 Documents.push_back(MyDocument("Some Document", false));
8580 }
8581};
8582
8583// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
8584// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
8585// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
8586// 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
8587// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
8588// give the impression of a flicker for one frame.
8589// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
8590// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
8591static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
8592{
8593 for (MyDocument& doc : app.Documents)
8594 {
8595 if (!doc.Open && doc.OpenPrev)
8596 ImGui::SetTabItemClosed(doc.Name);
8597 doc.OpenPrev = doc.Open;
8598 }
8599}
8600
8601void ShowExampleAppDocuments(bool* p_open)
8602{
8603 static ExampleAppDocuments app;
8604
8605 // Options
8606 enum Target
8607 {
8608 Target_None,
8609 Target_Tab, // Create documents as local tab into a local tab bar
8610 Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace
8611 };
8612 static Target opt_target = Target_Tab;
8613 static bool opt_reorderable = true;
8614 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
8615
8616 // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
8617 // that we emit gets docked into the same spot as the parent window ("Example: Documents").
8618 // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
8619 // not visible, which in turn would stop submitting the "Eggplant" window.
8620 // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
8621 // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
8622
8623 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
8624 if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
8625 {
8626 ImGui::End();
8627 return;
8628 }
8629
8630 // Menu
8631 if (ImGui::BeginMenuBar())
8632 {
8633 if (ImGui::BeginMenu("File"))
8634 {
8635 int open_count = 0;
8636 for (MyDocument& doc : app.Documents)
8637 open_count += doc.Open ? 1 : 0;
8638
8639 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
8640 {
8641 for (MyDocument& doc : app.Documents)
8642 if (!doc.Open && ImGui::MenuItem(doc.Name))
8643 doc.DoOpen();
8644 ImGui::EndMenu();
8645 }
8646 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
8647 for (MyDocument& doc : app.Documents)
8648 doc.DoQueueClose();
8649 if (ImGui::MenuItem("Exit", "Ctrl+F4") && p_open)
8650 *p_open = false;
8651 ImGui::EndMenu();
8652 }
8653 ImGui::EndMenuBar();
8654 }
8655
8656 // [Debug] List documents with one checkbox for each
8657 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
8658 {
8659 MyDocument& doc = app.Documents[doc_n];
8660 if (doc_n > 0)
8661 ImGui::SameLine();
8662 ImGui::PushID(&doc);
8663 if (ImGui::Checkbox(doc.Name, &doc.Open))
8664 if (!doc.Open)
8665 doc.DoForceClose();
8666 ImGui::PopID();
8667 }
8668 ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
8669 ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
8670 ImGui::PopItemWidth();
8671 bool redock_all = false;
8672 if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
8673 if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
8674
8675 ImGui::Separator();
8676
8677 // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
8678 // They have multiple effects:
8679 // - Display a dot next to the title.
8680 // - Tab is selected when clicking the X close button.
8681 // - Closure is not assumed (will wait for user to stop submitting the tab).
8682 // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
8683 // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
8684 // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
8685 // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
8686
8687 // Tabs
8688 if (opt_target == Target_Tab)
8689 {
8690 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
8691 if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
8692 {
8693 if (opt_reorderable)
8694 NotifyOfDocumentsClosedElsewhere(app);
8695
8696 // [DEBUG] Stress tests
8697 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
8698 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
8699
8700 // Submit Tabs
8701 for (MyDocument& doc : app.Documents)
8702 {
8703 if (!doc.Open)
8704 continue;
8705
8706 ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
8707 bool visible = ImGui::BeginTabItem(doc.Name, &doc.Open, tab_flags);
8708
8709 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
8710 if (!doc.Open && doc.Dirty)
8711 {
8712 doc.Open = true;
8713 doc.DoQueueClose();
8714 }
8715
8717 if (visible)
8718 {
8720 ImGui::EndTabItem();
8721 }
8722 }
8723
8724 ImGui::EndTabBar();
8725 }
8726 }
8727 else if (opt_target == Target_DockSpaceAndWindow)
8728 {
8729 if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
8730 {
8731 NotifyOfDocumentsClosedElsewhere(app);
8732
8733 // Create a DockSpace node where any window can be docked
8734 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
8735 ImGui::DockSpace(dockspace_id);
8736
8737 // Create Windows
8738 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
8739 {
8740 MyDocument* doc = &app.Documents[doc_n];
8741 if (!doc->Open)
8742 continue;
8743
8744 ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
8745 ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
8746 bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
8747
8748 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
8749 if (!doc->Open && doc->Dirty)
8750 {
8751 doc->Open = true;
8752 doc->DoQueueClose();
8753 }
8754
8756 if (visible)
8758
8759 ImGui::End();
8760 }
8761 }
8762 else
8763 {
8764 ShowDockingDisabledMessage();
8765 }
8766 }
8767
8768 // Early out other contents
8769 if (!window_contents_visible)
8770 {
8771 ImGui::End();
8772 return;
8773 }
8774
8775 // Update closing queue
8776 static ImVector<MyDocument*> close_queue;
8777 if (close_queue.empty())
8778 {
8779 // Close queue is locked once we started a popup
8780 for (MyDocument& doc : app.Documents)
8781 if (doc.WantClose)
8782 {
8783 doc.WantClose = false;
8784 close_queue.push_back(&doc);
8785 }
8786 }
8787
8788 // Display closing confirmation UI
8789 if (!close_queue.empty())
8790 {
8791 int close_queue_unsaved_documents = 0;
8792 for (int n = 0; n < close_queue.Size; n++)
8793 if (close_queue[n]->Dirty)
8794 close_queue_unsaved_documents++;
8795
8796 if (close_queue_unsaved_documents == 0)
8797 {
8798 // Close documents when all are unsaved
8799 for (int n = 0; n < close_queue.Size; n++)
8800 close_queue[n]->DoForceClose();
8801 close_queue.clear();
8802 }
8803 else
8804 {
8805 if (!ImGui::IsPopupOpen("Save?"))
8806 ImGui::OpenPopup("Save?");
8807 if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
8808 {
8809 ImGui::Text("Save change to the following items?");
8810 float item_height = ImGui::GetTextLineHeightWithSpacing();
8811 if (ImGui::BeginChild(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height), ImGuiChildFlags_FrameStyle))
8812 {
8813 for (int n = 0; n < close_queue.Size; n++)
8814 if (close_queue[n]->Dirty)
8815 ImGui::Text("%s", close_queue[n]->Name);
8816 }
8817 ImGui::EndChild();
8818
8819 ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
8820 if (ImGui::Button("Yes", button_size))
8821 {
8822 for (int n = 0; n < close_queue.Size; n++)
8823 {
8824 if (close_queue[n]->Dirty)
8825 close_queue[n]->DoSave();
8826 close_queue[n]->DoForceClose();
8827 }
8828 close_queue.clear();
8829 ImGui::CloseCurrentPopup();
8830 }
8831 ImGui::SameLine();
8832 if (ImGui::Button("No", button_size))
8833 {
8834 for (int n = 0; n < close_queue.Size; n++)
8835 close_queue[n]->DoForceClose();
8836 close_queue.clear();
8837 ImGui::CloseCurrentPopup();
8838 }
8839 ImGui::SameLine();
8840 if (ImGui::Button("Cancel", button_size))
8841 {
8842 close_queue.clear();
8843 ImGui::CloseCurrentPopup();
8844 }
8845 ImGui::EndPopup();
8846 }
8847 }
8848 }
8849
8850 ImGui::End();
8851}
8852
8853// End of Demo code
8854#else
8855
8856void ImGui::ShowAboutWindow(bool*) {}
8857void ImGui::ShowDemoWindow(bool*) {}
8858void ImGui::ShowUserGuide() {}
8859void ImGui::ShowStyleEditor(ImGuiStyle*) {}
8860
8861#endif
8862
8863#endif // #ifndef IMGUI_DISABLE
#define IM_NEWLINE
#define IM_CLAMP(V, MN, MX)
#define IMGUI_CDECL
void * GImGuiDemoMarkerCallbackUserData
#define IM_MAX(A, B)
ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback
#define PRIu64
void(* ImGuiDemoMarkerCallback)(const char *file, int line, const char *section, void *user_data)
#define PRId64
#define IMGUI_DEMO_MARKER(section)
IMGUI_API void ShowFontAtlas(ImFontAtlas *atlas)
Definition imgui.cc:19836
auto CalcTextSize(std::string_view str)
Definition ImGuiUtils.hh:37
void TextUnformatted(const std::string &str)
Definition ImGuiUtils.hh:24
constexpr double e
Definition Math.hh:21
constexpr double log(double x)
Definition cstd.hh:208
void ID(const char *str_id, std::invocable<> auto next)
Definition ImGuiCpp.hh:244
void Tooltip(std::invocable<> auto next)
Definition ImGuiCpp.hh:378
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
size_t size(std::string_view utf8)
auto filter(ForwardRange &&range, Predicate pred)
Definition view.hh:538
constexpr auto values(Map &&map)
Definition view.hh:531
void Draw(const char *title, bool *p_open)
int TextEditCallback(ImGuiInputTextCallbackData *data)
ImVector< char * > History
ImVector< const char * > Commands
static int TextEditCallbackStub(ImGuiInputTextCallbackData *data)
static void Strtrim(char *s)
static int Stricmp(const char *s1, const char *s2)
ImGuiTextFilter Filter
void AddLog(const char *fmt,...) IM_FMTARGS(2)
static int Strnicmp(const char *s1, const char *s2, int n)
void ExecCommand(const char *command_line)
static char * Strdup(const char *s)
ImVector< char * > Items
ImVector< MyDocument > Documents
ImGuiTextFilter Filter
void Draw(const char *title, bool *p_open=NULL)
ImGuiTextBuffer Buf
ImVector< int > LineOffsets
void AddLog(const char *fmt,...) IM_FMTARGS(2)
void DoQueueClose()
const char * Name
void DoOpen()
MyDocument(const char *name, bool open=true, const ImVec4 &color=ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
void DoSave()
static void DisplayContents(MyDocument *doc)
void DoForceClose()
static void DisplayContextMenu(MyDocument *doc)
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)