1 // dear imgui, v1.79 WIP
2 // (demo code)
3 
4 // Help:
5 // - Read FAQ at http://dearimgui.org/faq
6 // - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase.
7 // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
8 // Read imgui.cpp for more details, documentation and comments.
9 // Get latest version at https://github.com/ocornut/imgui
10 
11 // Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
12 // Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other
13 // coders will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available
14 // debug menu of your game/app! Removing this file from your project is hindering access to documentation for everyone
15 // in your team, likely leading you to poorer usage of the library.
16 // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
17 // If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
18 // linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
19 // In other situation, whenever you have Dear ImGui available you probably want this to be available for reference.
20 // Thank you,
21 // -Your beloved friend, imgui_demo.cpp (which you won't delete)
22 
23 // Message to beginner C/C++ programmers about the meaning of the 'static' keyword:
24 // In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls,
25 // so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to
26 // gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller
27 // in size. It also happens to be a convenient way of storing simple UI related information as long as your function
28 // doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code,
29 // but most of the real data you would be editing is likely going to be stored outside your functions.
30 
31 // The Demo code in this file is designed to be easy to copy-and-paste in into your application!
32 // Because of this:
33 // - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
34 // - We try to declare static variables in the local scope, as close as possible to the code using them.
35 // - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
36 // - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
37 //   by imgui_internal.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional
38 //   and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
39 //   Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
40 
41 /*
42 
43 Index of this file:
44 
45 // [SECTION] Forward Declarations, Helpers
46 // [SECTION] Demo Window / ShowDemoWindow()
47 // [SECTION] About Window / ShowAboutWindow()
48 // [SECTION] Style Editor / ShowStyleEditor()
49 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
50 // [SECTION] Example App: Debug Console / ShowExampleAppConsole()
51 // [SECTION] Example App: Debug Log / ShowExampleAppLog()
52 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
53 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
54 // [SECTION] Example App: Long Text / ShowExampleAppLongText()
55 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
56 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
57 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
58 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
59 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
60 // [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
61 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
62 
63 */
64 
65 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
66 #define _CRT_SECURE_NO_WARNINGS
67 #endif
68 
69 #include "imgui.h"
70 #ifndef IMGUI_DISABLE
71 
72 #include <ctype.h>          // toupper
73 #include <limits.h>         // INT_MIN, INT_MAX
74 #include <math.h>           // sqrtf, powf, cosf, sinf, floorf, ceilf
75 #include <stdio.h>          // vsnprintf, sscanf, printf
76 #include <stdlib.h>         // NULL, malloc, free, atoi
77 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
78 #include <stddef.h>         // intptr_t
79 #else
80 #include <stdint.h>         // intptr_t
81 #endif
82 
83 // Visual Studio warnings
84 #ifdef _MSC_VER
85 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
86 #endif
87 
88 // Clang/GCC warnings with -Weverything
89 #if defined(__clang__)
90 #if __has_warning("-Wunknown-warning-option")
91 #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!
92 #endif
93 #pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
94 #pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                           // yes, they are more terse.
95 #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)
96 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning: cast to 'void *' from smaller integer type
97 #pragma clang diagnostic ignored "-Wformat-security"                // warning: format string is not a string literal
98 #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.
99 #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.
100 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                   // some standard header variations use #define NULL 0
101 #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.
102 #pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
103 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
104 #elif defined(__GNUC__)
105 #pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
106 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
107 #pragma GCC diagnostic ignored "-Wformat-security"          // warning: format string is not a string literal (potentially insecure)
108 #pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
109 #pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
110 #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.
111 #endif
112 
113 // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
114 #ifdef _WIN32
115 #define IM_NEWLINE  "\r\n"
116 #else
117 #define IM_NEWLINE  "\n"
118 #endif
119 
120 // Helpers
121 #if defined(_MSC_VER) && !defined(snprintf)
122 #define snprintf    _snprintf
123 #endif
124 #if defined(_MSC_VER) && !defined(vsnprintf)
125 #define vsnprintf   _vsnprintf
126 #endif
127 
128 // Helpers macros
129 // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
130 // but making an exception here as those are largely simplifying code...
131 // In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
132 #define IM_MIN(A, B)            (((A) < (B)) ? (A) : (B))
133 #define IM_MAX(A, B)            (((A) >= (B)) ? (A) : (B))
134 #define IM_CLAMP(V, MN, MX)     ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
135 
136 //-----------------------------------------------------------------------------
137 // [SECTION] Forward Declarations, Helpers
138 //-----------------------------------------------------------------------------
139 
140 #if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
141 
142 // Forward Declarations
143 static void ShowExampleAppDockSpace(bool* p_open);
144 static void ShowExampleAppDocuments(bool* p_open);
145 static void ShowExampleAppMainMenuBar();
146 static void ShowExampleAppConsole(bool* p_open);
147 static void ShowExampleAppLog(bool* p_open);
148 static void ShowExampleAppLayout(bool* p_open);
149 static void ShowExampleAppPropertyEditor(bool* p_open);
150 static void ShowExampleAppLongText(bool* p_open);
151 static void ShowExampleAppAutoResize(bool* p_open);
152 static void ShowExampleAppConstrainedResize(bool* p_open);
153 static void ShowExampleAppSimpleOverlay(bool* p_open);
154 static void ShowExampleAppWindowTitles(bool* p_open);
155 static void ShowExampleAppCustomRendering(bool* p_open);
156 static void ShowExampleMenuFile();
157 
158 // Helper to display a little (?) mark which shows a tooltip when hovered.
159 // In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
HelpMarker(const char * desc)160 static void HelpMarker(const char* desc)
161 {
162     ImGui::TextDisabled("(?)");
163     if (ImGui::IsItemHovered())
164     {
165         ImGui::BeginTooltip();
166         ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
167         ImGui::TextUnformatted(desc);
168         ImGui::PopTextWrapPos();
169         ImGui::EndTooltip();
170     }
171 }
172 
ShowDockingDisabledMessage()173 static void ShowDockingDisabledMessage()
174 {
175     ImGuiIO& io = ImGui::GetIO();
176     ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
177     ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
178     ImGui::SameLine(0.0f, 0.0f);
179     if (ImGui::SmallButton("click here"))
180         io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
181 }
182 
183 // Helper to display basic user controls.
ShowUserGuide()184 void ImGui::ShowUserGuide()
185 {
186     ImGuiIO& io = ImGui::GetIO();
187     ImGui::BulletText("Double-click on title bar to collapse window.");
188     ImGui::BulletText(
189         "Click and drag on lower corner to resize window\n"
190         "(double-click to auto fit window to its contents).");
191     ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
192     ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
193     if (io.FontAllowUserScaling)
194         ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
195     ImGui::BulletText("While inputing text:\n");
196     ImGui::Indent();
197     ImGui::BulletText("CTRL+Left/Right to word jump.");
198     ImGui::BulletText("CTRL+A or double-click to select all.");
199     ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
200     ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
201     ImGui::BulletText("ESCAPE to revert.");
202     ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
203     ImGui::Unindent();
204     ImGui::BulletText("With keyboard navigation enabled:");
205     ImGui::Indent();
206     ImGui::BulletText("Arrow keys to navigate.");
207     ImGui::BulletText("Space to activate a widget.");
208     ImGui::BulletText("Return to input text into a widget.");
209     ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
210     ImGui::BulletText("Alt to jump to the menu layer of a window.");
211     ImGui::BulletText("CTRL+Tab to select a window.");
212     ImGui::Unindent();
213 }
214 
215 //-----------------------------------------------------------------------------
216 // [SECTION] Demo Window / ShowDemoWindow()
217 //-----------------------------------------------------------------------------
218 // - ShowDemoWindowWidgets()
219 // - ShowDemoWindowLayout()
220 // - ShowDemoWindowPopups()
221 // - ShowDemoWindowColumns()
222 // - ShowDemoWindowMisc()
223 //-----------------------------------------------------------------------------
224 
225 // We split the contents of the big ShowDemoWindow() function into smaller functions
226 // (because the link time of very large functions grow non-linearly)
227 static void ShowDemoWindowWidgets();
228 static void ShowDemoWindowLayout();
229 static void ShowDemoWindowPopups();
230 static void ShowDemoWindowColumns();
231 static void ShowDemoWindowMisc();
232 
233 // Demonstrate most Dear ImGui features (this is big function!)
234 // You may execute this function to experiment with the UI and understand what it does.
235 // You may then search for keywords in the code when you are interested by a specific feature.
ShowDemoWindow(bool * p_open)236 void ImGui::ShowDemoWindow(bool* p_open)
237 {
238     // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
239     // Most ImGui functions would normally just crash if the context is missing.
240     IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!");
241 
242     // Examples Apps (accessible from the "Examples" menu)
243     static bool show_app_main_menu_bar = false;
244     static bool show_app_dockspace = false;
245     static bool show_app_documents = false;
246 
247     static bool show_app_console = false;
248     static bool show_app_log = false;
249     static bool show_app_layout = false;
250     static bool show_app_property_editor = false;
251     static bool show_app_long_text = false;
252     static bool show_app_auto_resize = false;
253     static bool show_app_constrained_resize = false;
254     static bool show_app_simple_overlay = false;
255     static bool show_app_window_titles = false;
256     static bool show_app_custom_rendering = false;
257 
258     if (show_app_main_menu_bar)       ShowExampleAppMainMenuBar();
259     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)
260     if (show_app_documents)           ShowExampleAppDocuments(&show_app_documents);     // Process the Document app next, as it may also use a DockSpace()
261 
262     if (show_app_console)             ShowExampleAppConsole(&show_app_console);
263     if (show_app_log)                 ShowExampleAppLog(&show_app_log);
264     if (show_app_layout)              ShowExampleAppLayout(&show_app_layout);
265     if (show_app_property_editor)     ShowExampleAppPropertyEditor(&show_app_property_editor);
266     if (show_app_long_text)           ShowExampleAppLongText(&show_app_long_text);
267     if (show_app_auto_resize)         ShowExampleAppAutoResize(&show_app_auto_resize);
268     if (show_app_constrained_resize)  ShowExampleAppConstrainedResize(&show_app_constrained_resize);
269     if (show_app_simple_overlay)      ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
270     if (show_app_window_titles)       ShowExampleAppWindowTitles(&show_app_window_titles);
271     if (show_app_custom_rendering)    ShowExampleAppCustomRendering(&show_app_custom_rendering);
272 
273     // Dear ImGui Apps (accessible from the "Tools" menu)
274     static bool show_app_metrics = false;
275     static bool show_app_style_editor = false;
276     static bool show_app_about = false;
277 
278     if (show_app_metrics)       { ImGui::ShowMetricsWindow(&show_app_metrics); }
279     if (show_app_about)         { ImGui::ShowAboutWindow(&show_app_about); }
280     if (show_app_style_editor)
281     {
282         ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor);
283         ImGui::ShowStyleEditor();
284         ImGui::End();
285     }
286 
287     // Demonstrate the various window flags. Typically you would just use the default!
288     static bool no_titlebar = false;
289     static bool no_scrollbar = false;
290     static bool no_menu = false;
291     static bool no_move = false;
292     static bool no_resize = false;
293     static bool no_collapse = false;
294     static bool no_close = false;
295     static bool no_nav = false;
296     static bool no_background = false;
297     static bool no_bring_to_front = false;
298     static bool no_docking = false;
299 
300     ImGuiWindowFlags window_flags = 0;
301     if (no_titlebar)        window_flags |= ImGuiWindowFlags_NoTitleBar;
302     if (no_scrollbar)       window_flags |= ImGuiWindowFlags_NoScrollbar;
303     if (!no_menu)           window_flags |= ImGuiWindowFlags_MenuBar;
304     if (no_move)            window_flags |= ImGuiWindowFlags_NoMove;
305     if (no_resize)          window_flags |= ImGuiWindowFlags_NoResize;
306     if (no_collapse)        window_flags |= ImGuiWindowFlags_NoCollapse;
307     if (no_nav)             window_flags |= ImGuiWindowFlags_NoNav;
308     if (no_background)      window_flags |= ImGuiWindowFlags_NoBackground;
309     if (no_bring_to_front)  window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
310     if (no_docking)         window_flags |= ImGuiWindowFlags_NoDocking;
311     if (no_close)           p_open = NULL; // Don't pass our bool* to Begin
312 
313     // We specify a default position/size in case there's no data in the .ini file.
314     // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
315     ImGuiViewport* main_viewport = ImGui::GetMainViewport();
316     ImGui::SetNextWindowPos(ImVec2(main_viewport->GetWorkPos().x + 650, main_viewport->GetWorkPos().y + 20), ImGuiCond_FirstUseEver);
317     ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
318 
319     // Main body of the Demo window starts here.
320     if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
321     {
322         // Early out if the window is collapsed, as an optimization.
323         ImGui::End();
324         return;
325     }
326 
327     // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
328 
329     // e.g. Use 2/3 of the space for widgets and 1/3 for labels (default)
330     //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);
331 
332     // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
333     ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
334 
335     // Menu Bar
336     if (ImGui::BeginMenuBar())
337     {
338         if (ImGui::BeginMenu("Menu"))
339         {
340             ShowExampleMenuFile();
341             ImGui::EndMenu();
342         }
343         if (ImGui::BeginMenu("Examples"))
344         {
345             ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
346             ImGui::MenuItem("Console", NULL, &show_app_console);
347             ImGui::MenuItem("Log", NULL, &show_app_log);
348             ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
349             ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
350             ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
351             ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
352             ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
353             ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
354             ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
355             ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
356             ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace);
357             ImGui::MenuItem("Documents", NULL, &show_app_documents);
358             ImGui::EndMenu();
359         }
360         if (ImGui::BeginMenu("Tools"))
361         {
362             ImGui::MenuItem("Metrics", NULL, &show_app_metrics);
363             ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
364             ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
365             ImGui::EndMenu();
366         }
367         ImGui::EndMenuBar();
368     }
369 
370     ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION);
371     ImGui::Spacing();
372 
373     if (ImGui::CollapsingHeader("Help"))
374     {
375         ImGui::Text("ABOUT THIS DEMO:");
376         ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
377         ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
378         ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
379                           "and Metrics (general purpose Dear ImGui debugging tool).");
380         ImGui::Separator();
381 
382         ImGui::Text("PROGRAMMER GUIDE:");
383         ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
384         ImGui::BulletText("See comments in imgui.cpp.");
385         ImGui::BulletText("See example applications in the examples/ folder.");
386         ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/");
387         ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
388         ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
389         ImGui::Separator();
390 
391         ImGui::Text("USER GUIDE:");
392         ImGui::ShowUserGuide();
393     }
394 
395     if (ImGui::CollapsingHeader("Configuration"))
396     {
397         ImGuiIO& io = ImGui::GetIO();
398 
399         if (ImGui::TreeNode("Configuration##2"))
400         {
401             ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard",    (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
402             ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad",     (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
403             ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
404             ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
405             ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
406             ImGui::CheckboxFlags("io.ConfigFlags: NoMouse",              (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouse);
407 
408             // The "NoMouse" option above can get us stuck with a disable mouse! Provide an alternative way to fix it:
409             if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
410             {
411                 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
412                 {
413                     ImGui::SameLine();
414                     ImGui::Text("<<PRESS SPACE TO DISABLE>>");
415                 }
416                 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space)))
417                     io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
418             }
419             ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
420             ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility.");
421 
422             ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
423             ImGui::SameLine(); HelpMarker(io.ConfigDockingWithShift ? "[beta] Use SHIFT to dock window into each others." : "[beta] Drag from title bar to dock windows into each others.");
424             if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
425             {
426                 ImGui::Indent();
427                 ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
428                 ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
429                 ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift);
430                 ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allows to drop in wider space, reduce visual noise)");
431                 ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
432                 ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
433                 ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
434                 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.");
435                 ImGui::Unindent();
436             }
437 
438             ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
439             ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
440             if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
441             {
442                 ImGui::Indent();
443                 ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
444                 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.");
445                 ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
446                 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away).");
447                 ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
448                 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the decoration right away).");
449                 ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
450                 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the parenting right away).");
451                 ImGui::Unindent();
452             }
453 
454             ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
455             ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting");
456             ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
457             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.");
458             ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
459             ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
460             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).");
461             ImGui::Text("Also see Style->Rendering for rendering options.");
462             ImGui::TreePop();
463             ImGui::Separator();
464         }
465 
466         if (ImGui::TreeNode("Backend Flags"))
467         {
468             HelpMarker(
469                 "Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\n"
470                 "Here we expose then as read-only fields to avoid breaking interactions with your back-end.");
471             // Make a local copy to avoid modifying actual back-end flags.
472             ImGuiBackendFlags backend_flags = io.BackendFlags;
473             ImGui::CheckboxFlags("io.BackendFlags: HasGamepad",             (unsigned int*)&backend_flags, ImGuiBackendFlags_HasGamepad);
474             ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors",        (unsigned int*)&backend_flags, ImGuiBackendFlags_HasMouseCursors);
475             ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos",         (unsigned int*)&backend_flags, ImGuiBackendFlags_HasSetMousePos);
476             ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports",   (unsigned int*)&backend_flags, ImGuiBackendFlags_PlatformHasViewports);
477             ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",(unsigned int*)&backend_flags, ImGuiBackendFlags_HasMouseHoveredViewport);
478             ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset",   (unsigned int*)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset);
479             ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports",   (unsigned int*)&backend_flags, ImGuiBackendFlags_RendererHasViewports);
480             ImGui::TreePop();
481             ImGui::Separator();
482         }
483 
484         if (ImGui::TreeNode("Style"))
485         {
486             HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
487             ImGui::ShowStyleEditor();
488             ImGui::TreePop();
489             ImGui::Separator();
490         }
491 
492         if (ImGui::TreeNode("Capture/Logging"))
493         {
494             HelpMarker(
495                 "The logging API redirects all text output so you can easily capture the content of "
496                 "a window or a block. Tree nodes can be automatically expanded.\n"
497                 "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
498             ImGui::LogButtons();
499 
500             HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
501             if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
502             {
503                 ImGui::LogToClipboard();
504                 ImGui::LogText("Hello, world!");
505                 ImGui::LogFinish();
506             }
507             ImGui::TreePop();
508         }
509     }
510 
511     if (ImGui::CollapsingHeader("Window options"))
512     {
513         ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150);
514         ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300);
515         ImGui::Checkbox("No menu", &no_menu);
516         ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150);
517         ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300);
518         ImGui::Checkbox("No collapse", &no_collapse);
519         ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150);
520         ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300);
521         ImGui::Checkbox("No background", &no_background);
522         ImGui::Checkbox("No bring to front", &no_bring_to_front);
523         ImGui::Checkbox("No docking", &no_docking);
524     }
525 
526     // All demo contents
527     ShowDemoWindowWidgets();
528     ShowDemoWindowLayout();
529     ShowDemoWindowPopups();
530     ShowDemoWindowColumns();
531     ShowDemoWindowMisc();
532 
533     // End of ShowDemoWindow()
534     ImGui::End();
535 }
536 
ShowDemoWindowWidgets()537 static void ShowDemoWindowWidgets()
538 {
539     if (!ImGui::CollapsingHeader("Widgets"))
540         return;
541 
542     if (ImGui::TreeNode("Basic"))
543     {
544         static int clicked = 0;
545         if (ImGui::Button("Button"))
546             clicked++;
547         if (clicked & 1)
548         {
549             ImGui::SameLine();
550             ImGui::Text("Thanks for clicking me!");
551         }
552 
553         static bool check = true;
554         ImGui::Checkbox("checkbox", &check);
555 
556         static int e = 0;
557         ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
558         ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
559         ImGui::RadioButton("radio c", &e, 2);
560 
561         // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
562         for (int i = 0; i < 7; i++)
563         {
564             if (i > 0)
565                 ImGui::SameLine();
566             ImGui::PushID(i);
567             ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
568             ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
569             ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
570             ImGui::Button("Click");
571             ImGui::PopStyleColor(3);
572             ImGui::PopID();
573         }
574 
575         // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
576         // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
577         // See 'Demo->Layout->Text Baseline Alignment' for details.
578         ImGui::AlignTextToFramePadding();
579         ImGui::Text("Hold to repeat:");
580         ImGui::SameLine();
581 
582         // Arrow buttons with Repeater
583         static int counter = 0;
584         float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
585         ImGui::PushButtonRepeat(true);
586         if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
587         ImGui::SameLine(0.0f, spacing);
588         if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
589         ImGui::PopButtonRepeat();
590         ImGui::SameLine();
591         ImGui::Text("%d", counter);
592 
593         ImGui::Text("Hover over me");
594         if (ImGui::IsItemHovered())
595             ImGui::SetTooltip("I am a tooltip");
596 
597         ImGui::SameLine();
598         ImGui::Text("- or me");
599         if (ImGui::IsItemHovered())
600         {
601             ImGui::BeginTooltip();
602             ImGui::Text("I am a fancy tooltip");
603             static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
604             ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
605             ImGui::EndTooltip();
606         }
607 
608         ImGui::Separator();
609 
610         ImGui::LabelText("label", "Value");
611 
612         {
613             // Using the _simplified_ one-liner Combo() api here
614             // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api.
615             const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
616             static int item_current = 0;
617             ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
618             ImGui::SameLine(); HelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n");
619         }
620 
621         {
622             // To wire InputText() with std::string or any other custom string type,
623             // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
624             static char str0[128] = "Hello, world!";
625             ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
626             ImGui::SameLine(); HelpMarker(
627                 "USER:\n"
628                 "Hold SHIFT or use mouse to select text.\n"
629                 "CTRL+Left/Right to word jump.\n"
630                 "CTRL+A or double-click to select all.\n"
631                 "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
632                 "CTRL+Z,CTRL+Y undo/redo.\n"
633                 "ESCAPE to revert.\n\n"
634                 "PROGRAMMER:\n"
635                 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
636                 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
637                 "in imgui_demo.cpp).");
638 
639             static char str1[128] = "";
640             ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
641 
642             static int i0 = 123;
643             ImGui::InputInt("input int", &i0);
644             ImGui::SameLine(); HelpMarker(
645                 "You can apply arithmetic operators +,*,/ on numerical values.\n"
646                 "  e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n"
647                 "Use +- to subtract.");
648 
649             static float f0 = 0.001f;
650             ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
651 
652             static double d0 = 999999.00000001;
653             ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
654 
655             static float f1 = 1.e10f;
656             ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
657             ImGui::SameLine(); HelpMarker(
658                 "You can input value using the scientific notation,\n"
659                 "  e.g. \"1e+8\" becomes \"100000000\".");
660 
661             static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
662             ImGui::InputFloat3("input float3", vec4a);
663         }
664 
665         {
666             static int i1 = 50, i2 = 42;
667             ImGui::DragInt("drag int", &i1, 1);
668             ImGui::SameLine(); HelpMarker(
669                 "Click and drag to edit value.\n"
670                 "Hold SHIFT/ALT for faster/slower edit.\n"
671                 "Double-click or CTRL+click to input value.");
672 
673             ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%");
674 
675             static float f1 = 1.00f, f2 = 0.0067f;
676             ImGui::DragFloat("drag float", &f1, 0.005f);
677             ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
678         }
679 
680         {
681             static int i1 = 0;
682             ImGui::SliderInt("slider int", &i1, -1, 3);
683             ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
684 
685             static float f1 = 0.123f, f2 = 0.0f;
686             ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
687             ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
688 
689             static float angle = 0.0f;
690             ImGui::SliderAngle("slider angle", &angle);
691 
692             // Using the format string to display a name instead of an integer.
693             // Here we completely omit '%d' from the format string, so it'll only display a name.
694             // This technique can also be used with DragInt().
695             enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
696             static int elem = Element_Fire;
697             const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
698             const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
699             ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name);
700             ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
701         }
702 
703         {
704             static float col1[3] = { 1.0f, 0.0f, 0.2f };
705             static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
706             ImGui::ColorEdit3("color 1", col1);
707             ImGui::SameLine(); HelpMarker(
708                 "Click on the colored square to open a color picker.\n"
709                 "Click and hold to use drag and drop.\n"
710                 "Right-click on the colored square to show options.\n"
711                 "CTRL+click on individual component to input value.\n");
712 
713             ImGui::ColorEdit4("color 2", col2);
714         }
715 
716         {
717             // List box
718             const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
719             static int item_current = 1;
720             ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4);
721 
722             //static int listbox_item_current2 = 2;
723             //ImGui::SetNextItemWidth(-1);
724             //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
725         }
726 
727         ImGui::TreePop();
728     }
729 
730     // Testing ImGuiOnceUponAFrame helper.
731     //static ImGuiOnceUponAFrame once;
732     //for (int i = 0; i < 5; i++)
733     //    if (once)
734     //        ImGui::Text("This will be displayed only once.");
735 
736     if (ImGui::TreeNode("Trees"))
737     {
738         if (ImGui::TreeNode("Basic trees"))
739         {
740             for (int i = 0; i < 5; i++)
741             {
742                 // Use SetNextItemOpen() so set the default state of a node to be open. We could
743                 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
744                 if (i == 0)
745                     ImGui::SetNextItemOpen(true, ImGuiCond_Once);
746 
747                 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
748                 {
749                     ImGui::Text("blah blah");
750                     ImGui::SameLine();
751                     if (ImGui::SmallButton("button")) {}
752                     ImGui::TreePop();
753                 }
754             }
755             ImGui::TreePop();
756         }
757 
758         if (ImGui::TreeNode("Advanced, with Selectable nodes"))
759         {
760             HelpMarker(
761                 "This is a more typical looking tree with selectable nodes.\n"
762                 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
763             static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
764             static bool align_label_with_current_x_position = false;
765             static bool test_drag_and_drop = false;
766             ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow",       (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
767             ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
768             ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth",    (unsigned int*)&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.");
769             ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth",     (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
770             ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
771             ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
772             ImGui::Text("Hello!");
773             if (align_label_with_current_x_position)
774                 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
775 
776             // 'selection_mask' is dumb representation of what may be user-side selection state.
777             //  You may retain selection state inside or outside your objects in whatever format you see fit.
778             // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
779             /// of the loop. May be a pointer to your own node type, etc.
780             static int selection_mask = (1 << 2);
781             int node_clicked = -1;
782             for (int i = 0; i < 6; i++)
783             {
784                 // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
785                 ImGuiTreeNodeFlags node_flags = base_flags;
786                 const bool is_selected = (selection_mask & (1 << i)) != 0;
787                 if (is_selected)
788                     node_flags |= ImGuiTreeNodeFlags_Selected;
789                 if (i < 3)
790                 {
791                     // Items 0..2 are Tree Node
792                     bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
793                     if (ImGui::IsItemClicked())
794                         node_clicked = i;
795                     if (test_drag_and_drop && ImGui::BeginDragDropSource())
796                     {
797                         ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
798                         ImGui::Text("This is a drag and drop source");
799                         ImGui::EndDragDropSource();
800                     }
801                     if (node_open)
802                     {
803                         ImGui::BulletText("Blah blah\nBlah Blah");
804                         ImGui::TreePop();
805                     }
806                 }
807                 else
808                 {
809                     // Items 3..5 are Tree Leaves
810                     // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
811                     // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
812                     node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
813                     ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
814                     if (ImGui::IsItemClicked())
815                         node_clicked = i;
816                     if (test_drag_and_drop && ImGui::BeginDragDropSource())
817                     {
818                         ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
819                         ImGui::Text("This is a drag and drop source");
820                         ImGui::EndDragDropSource();
821                     }
822                 }
823             }
824             if (node_clicked != -1)
825             {
826                 // Update selection state
827                 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
828                 if (ImGui::GetIO().KeyCtrl)
829                     selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
830                 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
831                     selection_mask = (1 << node_clicked);           // Click to single-select
832             }
833             if (align_label_with_current_x_position)
834                 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
835             ImGui::TreePop();
836         }
837         ImGui::TreePop();
838     }
839 
840     if (ImGui::TreeNode("Collapsing Headers"))
841     {
842         static bool closable_group = true;
843         ImGui::Checkbox("Show 2nd header", &closable_group);
844         if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
845         {
846             ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
847             for (int i = 0; i < 5; i++)
848                 ImGui::Text("Some content %d", i);
849         }
850         if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
851         {
852             ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
853             for (int i = 0; i < 5; i++)
854                 ImGui::Text("More content %d", i);
855         }
856         /*
857         if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
858             ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
859         */
860         ImGui::TreePop();
861     }
862 
863     if (ImGui::TreeNode("Bullets"))
864     {
865         ImGui::BulletText("Bullet point 1");
866         ImGui::BulletText("Bullet point 2\nOn multiple lines");
867         if (ImGui::TreeNode("Tree node"))
868         {
869             ImGui::BulletText("Another bullet point");
870             ImGui::TreePop();
871         }
872         ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
873         ImGui::Bullet(); ImGui::SmallButton("Button");
874         ImGui::TreePop();
875     }
876 
877     if (ImGui::TreeNode("Text"))
878     {
879         if (ImGui::TreeNode("Colored Text"))
880         {
881             // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
882             ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
883             ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
884             ImGui::TextDisabled("Disabled");
885             ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
886             ImGui::TreePop();
887         }
888 
889         if (ImGui::TreeNode("Word Wrapping"))
890         {
891             // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
892             ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages.");
893             ImGui::Spacing();
894 
895             static float wrap_width = 200.0f;
896             ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
897 
898             ImDrawList* draw_list = ImGui::GetWindowDrawList();
899             for (int n = 0; n < 2; n++)
900             {
901                 ImGui::Text("Test paragraph %d:", n);
902                 ImVec2 pos = ImGui::GetCursorScreenPos();
903                 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
904                 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
905                 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
906                 if (n == 0)
907                     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);
908                 if (n == 1)
909                     ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee   ffffffff. gggggggg!hhhhhhhh");
910 
911                 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
912                 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
913                 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
914                 ImGui::PopTextWrapPos();
915             }
916 
917             ImGui::TreePop();
918         }
919 
920         if (ImGui::TreeNode("UTF-8 Text"))
921         {
922             // UTF-8 test with Japanese characters
923             // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
924             // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
925             // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
926             //   can save your source files as 'UTF-8 without signature').
927             // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
928             //   CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
929             //   Don't do this in your application! Please use u8"text in any language" in your application!
930             // Note that characters values are preserved even by InputText() if the font cannot be displayed,
931             // so you can safely copy & paste garbled characters into another application.
932             ImGui::TextWrapped(
933                 "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. "
934                 "Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. "
935                 "Read docs/FONTS.md for details.");
936             ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string.
937             ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
938             static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
939             //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
940             ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
941             ImGui::TreePop();
942         }
943         ImGui::TreePop();
944     }
945 
946     if (ImGui::TreeNode("Images"))
947     {
948         ImGuiIO& io = ImGui::GetIO();
949         ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!");
950 
951         // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
952         // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
953         // will be passed to the rendering back-end via the ImDrawCmd structure.
954         // If you use one of the default imgui_impl_XXXX.cpp rendering back-end, they all have comments at the top
955         // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
956         // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
957         // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
958         // More:
959         // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
960         //   to ImGui::Image(), and gather width/height through your own functions, etc.
961         // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
962         //   it will help you debug issues if you are confused about it.
963         // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
964         // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
965         // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
966         ImTextureID my_tex_id = io.Fonts->TexID;
967         float my_tex_w = (float)io.Fonts->TexWidth;
968         float my_tex_h = (float)io.Fonts->TexHeight;
969         {
970             ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
971             ImVec2 pos = ImGui::GetCursorScreenPos();
972             ImVec2 uv_min = ImVec2(0.0f, 0.0f);                 // Top-left
973             ImVec2 uv_max = ImVec2(1.0f, 1.0f);                 // Lower-right
974             ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);   // No tint
975             ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white
976             ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
977             if (ImGui::IsItemHovered())
978             {
979                 ImGui::BeginTooltip();
980                 float region_sz = 32.0f;
981                 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
982                 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
983                 float zoom = 4.0f;
984                 if (region_x < 0.0f) { region_x = 0.0f; }
985                 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
986                 if (region_y < 0.0f) { region_y = 0.0f; }
987                 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
988                 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
989                 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
990                 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
991                 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
992                 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
993                 ImGui::EndTooltip();
994             }
995         }
996         ImGui::TextWrapped("And now some textured buttons..");
997         static int pressed_count = 0;
998         for (int i = 0; i < 8; i++)
999         {
1000             ImGui::PushID(i);
1001             int frame_padding = -1 + i;                             // -1 == uses default padding (style.FramePadding)
1002             ImVec2 size = ImVec2(32.0f, 32.0f);                     // Size of the image we want to make visible
1003             ImVec2 uv0 = ImVec2(0.0f, 0.0f);                        // UV coordinates for lower-left
1004             ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32 / my_tex_h);   // UV coordinates for (32,32) in our texture
1005             ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);         // Black background
1006             ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);       // No tint
1007             if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col))
1008                 pressed_count += 1;
1009             ImGui::PopID();
1010             ImGui::SameLine();
1011         }
1012         ImGui::NewLine();
1013         ImGui::Text("Pressed %d times.", pressed_count);
1014         ImGui::TreePop();
1015     }
1016 
1017     if (ImGui::TreeNode("Combo"))
1018     {
1019         // Expose flags as checkbox for the demo
1020         static ImGuiComboFlags flags = 0;
1021         ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft);
1022         ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1023         if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton))
1024             flags &= ~ImGuiComboFlags_NoPreview;     // Clear the other flag, as we cannot combine both
1025         if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview))
1026             flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both
1027 
1028         // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1029         // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1030         // stored in the object itself, etc.)
1031         const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1032         static int item_current_idx = 0;                    // Here our selection data is an index.
1033         const char* combo_label = items[item_current_idx];  // Label to preview before opening the combo (technically could be anything)(
1034         if (ImGui::BeginCombo("combo 1", combo_label, flags))
1035         {
1036             for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1037             {
1038                 const bool is_selected = (item_current_idx == n);
1039                 if (ImGui::Selectable(items[n], is_selected))
1040                     item_current_idx = n;
1041 
1042                 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1043                 if (is_selected)
1044                     ImGui::SetItemDefaultFocus();
1045             }
1046             ImGui::EndCombo();
1047         }
1048 
1049         // Simplified one-liner Combo() API, using values packed in a single constant string
1050         static int item_current_2 = 0;
1051         ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1052 
1053         // Simplified one-liner Combo() using an array of const char*
1054         static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1055         ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
1056 
1057         // Simplified one-liner Combo() using an accessor function
1058         struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } };
1059         static int item_current_4 = 0;
1060         ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items));
1061 
1062         ImGui::TreePop();
1063     }
1064 
1065     if (ImGui::TreeNode("Selectables"))
1066     {
1067         // Selectable() has 2 overloads:
1068         // - The one taking "bool selected" as a read-only selection information.
1069         //   When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1070         // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1071         // The earlier is more flexible, as in real application your selection may be stored in many different ways
1072         // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1073         if (ImGui::TreeNode("Basic"))
1074         {
1075             static bool selection[5] = { false, true, false, false, false };
1076             ImGui::Selectable("1. I am selectable", &selection[0]);
1077             ImGui::Selectable("2. I am selectable", &selection[1]);
1078             ImGui::Text("3. I am not selectable");
1079             ImGui::Selectable("4. I am selectable", &selection[3]);
1080             if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick))
1081                 if (ImGui::IsMouseDoubleClicked(0))
1082                     selection[4] = !selection[4];
1083             ImGui::TreePop();
1084         }
1085         if (ImGui::TreeNode("Selection State: Single Selection"))
1086         {
1087             static int selected = -1;
1088             for (int n = 0; n < 5; n++)
1089             {
1090                 char buf[32];
1091                 sprintf(buf, "Object %d", n);
1092                 if (ImGui::Selectable(buf, selected == n))
1093                     selected = n;
1094             }
1095             ImGui::TreePop();
1096         }
1097         if (ImGui::TreeNode("Selection State: Multiple Selection"))
1098         {
1099             HelpMarker("Hold CTRL and click to select multiple items.");
1100             static bool selection[5] = { false, false, false, false, false };
1101             for (int n = 0; n < 5; n++)
1102             {
1103                 char buf[32];
1104                 sprintf(buf, "Object %d", n);
1105                 if (ImGui::Selectable(buf, selection[n]))
1106                 {
1107                     if (!ImGui::GetIO().KeyCtrl)    // Clear selection when CTRL is not held
1108                         memset(selection, 0, sizeof(selection));
1109                     selection[n] ^= 1;
1110                 }
1111             }
1112             ImGui::TreePop();
1113         }
1114         if (ImGui::TreeNode("Rendering more text into the same line"))
1115         {
1116             // Using the Selectable() override that takes "bool* p_selected" parameter,
1117             // this function toggle your bool value automatically.
1118             static bool selected[3] = { false, false, false };
1119             ImGui::Selectable("main.c",    &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
1120             ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes");
1121             ImGui::Selectable("Hello.h",   &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
1122             ImGui::TreePop();
1123         }
1124         if (ImGui::TreeNode("In columns"))
1125         {
1126             ImGui::Columns(3, NULL, false);
1127             static bool selected[16] = {};
1128             for (int i = 0; i < 16; i++)
1129             {
1130                 char label[32]; sprintf(label, "Item %d", i);
1131                 if (ImGui::Selectable(label, &selected[i])) {}
1132                 ImGui::NextColumn();
1133             }
1134             ImGui::Columns(1);
1135             ImGui::TreePop();
1136         }
1137         if (ImGui::TreeNode("Grid"))
1138         {
1139             static int selected[4 * 4] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
1140             for (int i = 0; i < 4 * 4; i++)
1141             {
1142                 ImGui::PushID(i);
1143                 if (ImGui::Selectable("Sailor", selected[i] != 0, 0, ImVec2(50, 50)))
1144                 {
1145                     // Toggle
1146                     selected[i] = !selected[i];
1147 
1148                     // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer.
1149                     // The second part of each test is unnecessary.
1150                     int x = i % 4;
1151                     int y = i / 4;
1152                     if (x > 0)           { selected[i - 1] ^= 1; }
1153                     if (x < 3 && i < 15) { selected[i + 1] ^= 1; }
1154                     if (y > 0 && i > 3)  { selected[i - 4] ^= 1; }
1155                     if (y < 3 && i < 12) { selected[i + 4] ^= 1; }
1156                 }
1157                 if ((i % 4) < 3) ImGui::SameLine();
1158                 ImGui::PopID();
1159             }
1160             ImGui::TreePop();
1161         }
1162         if (ImGui::TreeNode("Alignment"))
1163         {
1164             HelpMarker(
1165                 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1166                 "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1167                 "left-align otherwise it becomes difficult to layout multiple items on a same line");
1168             static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1169             for (int y = 0; y < 3; y++)
1170             {
1171                 for (int x = 0; x < 3; x++)
1172                 {
1173                     ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1174                     char name[32];
1175                     sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
1176                     if (x > 0) ImGui::SameLine();
1177                     ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
1178                     ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
1179                     ImGui::PopStyleVar();
1180                 }
1181             }
1182             ImGui::TreePop();
1183         }
1184         ImGui::TreePop();
1185     }
1186 
1187     // To wire InputText() with std::string or any other custom string type,
1188     // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1189     if (ImGui::TreeNode("Text Input"))
1190     {
1191         if (ImGui::TreeNode("Multi-line Text Input"))
1192         {
1193             // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1194             // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1195             static char text[1024 * 16] =
1196                 "/*\n"
1197                 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1198                 " the hexadecimal encoding of one offending instruction,\n"
1199                 " more formally, the invalid operand with locked CMPXCHG8B\n"
1200                 " instruction bug, is a design flaw in the majority of\n"
1201                 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1202                 " processors (all in the P5 microarchitecture).\n"
1203                 "*/\n\n"
1204                 "label:\n"
1205                 "\tlock cmpxchg8b eax\n";
1206 
1207             static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1208             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)");
1209             ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly);
1210             ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput);
1211             ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
1212             ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1213             ImGui::TreePop();
1214         }
1215 
1216         if (ImGui::TreeNode("Filtered Text Input"))
1217         {
1218             struct TextFilters
1219             {
1220                 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i'
1221                 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1222                 {
1223                     if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
1224                         return 0;
1225                     return 1;
1226                 }
1227             };
1228 
1229             static char buf1[64] = ""; ImGui::InputText("default",     buf1, 64);
1230             static char buf2[64] = ""; ImGui::InputText("decimal",     buf2, 64, ImGuiInputTextFlags_CharsDecimal);
1231             static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1232             static char buf4[64] = ""; ImGui::InputText("uppercase",   buf4, 64, ImGuiInputTextFlags_CharsUppercase);
1233             static char buf5[64] = ""; ImGui::InputText("no blank",    buf5, 64, ImGuiInputTextFlags_CharsNoBlank);
1234             static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters);
1235             ImGui::TreePop();
1236         }
1237 
1238         if (ImGui::TreeNode("Password Input"))
1239         {
1240             static char password[64] = "password123";
1241             ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1242             ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1243             ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1244             ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
1245             ImGui::TreePop();
1246         }
1247 
1248         if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
1249         {
1250             struct Funcs
1251             {
1252                 static int MyCallback(ImGuiInputTextCallbackData* data)
1253                 {
1254                     if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1255                     {
1256                         data->InsertChars(data->CursorPos, "..");
1257                     }
1258                     else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1259                     {
1260                         if (data->EventKey == ImGuiKey_UpArrow)
1261                         {
1262                             data->DeleteChars(0, data->BufTextLen);
1263                             data->InsertChars(0, "Pressed Up!");
1264                             data->SelectAll();
1265                         }
1266                         else if (data->EventKey == ImGuiKey_DownArrow)
1267                         {
1268                             data->DeleteChars(0, data->BufTextLen);
1269                             data->InsertChars(0, "Pressed Down!");
1270                             data->SelectAll();
1271                         }
1272                     }
1273                     else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1274                     {
1275                         // Toggle casing of first character
1276                         char c = data->Buf[0];
1277                         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1278                         data->BufDirty = true;
1279 
1280                         // Increment a counter
1281                         int* p_int = (int*)data->UserData;
1282                         *p_int = *p_int + 1;
1283                     }
1284                     return 0;
1285                 }
1286             };
1287             static char buf1[64];
1288             ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
1289             ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1290 
1291             static char buf2[64];
1292             ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
1293             ImGui::SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1294 
1295             static char buf3[64];
1296             static int edit_count = 0;
1297             ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
1298             ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits.");
1299             ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
1300 
1301             ImGui::TreePop();
1302         }
1303 
1304         if (ImGui::TreeNode("Resize Callback"))
1305         {
1306             // To wire InputText() with std::string or any other custom string type,
1307             // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1308             // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1309             HelpMarker(
1310                 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1311                 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1312             struct Funcs
1313             {
1314                 static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1315                 {
1316                     if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1317                     {
1318                         ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1319                         IM_ASSERT(my_str->begin() == data->Buf);
1320                         my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1321                         data->Buf = my_str->begin();
1322                     }
1323                     return 0;
1324                 }
1325 
1326                 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1327                 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1328                 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1329                 {
1330                     IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1331                     return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
1332                 }
1333             };
1334 
1335             // For this demo we are using ImVector as a string container.
1336             // Note that because we need to store a terminating zero character, our size/capacity are 1 more
1337             // than usually reported by a typical string class.
1338             static ImVector<char> my_str;
1339             if (my_str.empty())
1340                 my_str.push_back(0);
1341             Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1342             ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1343             ImGui::TreePop();
1344         }
1345 
1346         ImGui::TreePop();
1347     }
1348 
1349     // Plot/Graph widgets are currently fairly limited.
1350     // Consider writing your own plotting widget, or using a third-party one
1351     // (for third-party Plot widgets, see 'Wiki->Useful Widgets' or https://github.com/ocornut/imgui/labels/plot%2Fgraph)
1352     if (ImGui::TreeNode("Plots Widgets"))
1353     {
1354         static bool animate = true;
1355         ImGui::Checkbox("Animate", &animate);
1356 
1357         static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1358         ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
1359 
1360         // Fill an array of contiguous float values to plot
1361         // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
1362         // and the sizeof() of your structure in the "stride" parameter.
1363         static float values[90] = {};
1364         static int values_offset = 0;
1365         static double refresh_time = 0.0;
1366         if (!animate || refresh_time == 0.0)
1367             refresh_time = ImGui::GetTime();
1368         while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
1369         {
1370             static float phase = 0.0f;
1371             values[values_offset] = cosf(phase);
1372             values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
1373             phase += 0.10f * values_offset;
1374             refresh_time += 1.0f / 60.0f;
1375         }
1376 
1377         // Plots can display overlay texts
1378         // (in this example, we will display an average value)
1379         {
1380             float average = 0.0f;
1381             for (int n = 0; n < IM_ARRAYSIZE(values); n++)
1382                 average += values[n];
1383             average /= (float)IM_ARRAYSIZE(values);
1384             char overlay[32];
1385             sprintf(overlay, "avg %f", average);
1386             ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
1387         }
1388         ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
1389 
1390         // Use functions to generate output
1391         // FIXME: This is rather awkward because current plot API only pass in indices.
1392         // We probably want an API passing floats and user provide sample rate/count.
1393         struct Funcs
1394         {
1395             static float Sin(void*, int i) { return sinf(i * 0.1f); }
1396             static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
1397         };
1398         static int func_type = 0, display_count = 70;
1399         ImGui::Separator();
1400         ImGui::SetNextItemWidth(100);
1401         ImGui::Combo("func", &func_type, "Sin\0Saw\0");
1402         ImGui::SameLine();
1403         ImGui::SliderInt("Sample count", &display_count, 1, 400);
1404         float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
1405         ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
1406         ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
1407         ImGui::Separator();
1408 
1409         // Animate a simple progress bar
1410         static float progress = 0.0f, progress_dir = 1.0f;
1411         if (animate)
1412         {
1413             progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
1414             if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
1415             if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
1416         }
1417 
1418         // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
1419         // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
1420         ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
1421         ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
1422         ImGui::Text("Progress Bar");
1423 
1424         float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
1425         char buf[32];
1426         sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
1427         ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
1428         ImGui::TreePop();
1429     }
1430 
1431     if (ImGui::TreeNode("Color/Picker Widgets"))
1432     {
1433         static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
1434 
1435         static bool alpha_preview = true;
1436         static bool alpha_half_preview = false;
1437         static bool drag_and_drop = true;
1438         static bool options_menu = true;
1439         static bool hdr = false;
1440         ImGui::Checkbox("With Alpha Preview", &alpha_preview);
1441         ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
1442         ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
1443         ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
1444         ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
1445         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);
1446 
1447         ImGui::Text("Color widget:");
1448         ImGui::SameLine(); HelpMarker(
1449             "Click on the colored square to open a color picker.\n"
1450             "CTRL+click on individual component to input value.\n");
1451         ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
1452 
1453         ImGui::Text("Color widget HSV with Alpha:");
1454         ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
1455 
1456         ImGui::Text("Color widget with Float Display:");
1457         ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
1458 
1459         ImGui::Text("Color button with Picker:");
1460         ImGui::SameLine(); HelpMarker(
1461             "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
1462             "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
1463             "be used for the tooltip and picker popup.");
1464         ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
1465 
1466         ImGui::Text("Color button with Custom Picker Popup:");
1467 
1468         // Generate a default palette. The palette will persist and can be edited.
1469         static bool saved_palette_init = true;
1470         static ImVec4 saved_palette[32] = {};
1471         if (saved_palette_init)
1472         {
1473             for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
1474             {
1475                 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
1476                     saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
1477                 saved_palette[n].w = 1.0f; // Alpha
1478             }
1479             saved_palette_init = false;
1480         }
1481 
1482         static ImVec4 backup_color;
1483         bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
1484         ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
1485         open_popup |= ImGui::Button("Palette");
1486         if (open_popup)
1487         {
1488             ImGui::OpenPopup("mypicker");
1489             backup_color = color;
1490         }
1491         if (ImGui::BeginPopup("mypicker"))
1492         {
1493             ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
1494             ImGui::Separator();
1495             ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
1496             ImGui::SameLine();
1497 
1498             ImGui::BeginGroup(); // Lock X position
1499             ImGui::Text("Current");
1500             ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
1501             ImGui::Text("Previous");
1502             if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
1503                 color = backup_color;
1504             ImGui::Separator();
1505             ImGui::Text("Palette");
1506             for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
1507             {
1508                 ImGui::PushID(n);
1509                 if ((n % 8) != 0)
1510                     ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
1511 
1512                 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
1513                 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
1514                     color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
1515 
1516                 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
1517                 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
1518                 if (ImGui::BeginDragDropTarget())
1519                 {
1520                     if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
1521                         memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
1522                     if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
1523                         memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
1524                     ImGui::EndDragDropTarget();
1525                 }
1526 
1527                 ImGui::PopID();
1528             }
1529             ImGui::EndGroup();
1530             ImGui::EndPopup();
1531         }
1532 
1533         ImGui::Text("Color button only:");
1534         static bool no_border = false;
1535         ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
1536         ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
1537 
1538         ImGui::Text("Color picker:");
1539         static bool alpha = true;
1540         static bool alpha_bar = true;
1541         static bool side_preview = true;
1542         static bool ref_color = false;
1543         static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
1544         static int display_mode = 0;
1545         static int picker_mode = 0;
1546         ImGui::Checkbox("With Alpha", &alpha);
1547         ImGui::Checkbox("With Alpha Bar", &alpha_bar);
1548         ImGui::Checkbox("With Side Preview", &side_preview);
1549         if (side_preview)
1550         {
1551             ImGui::SameLine();
1552             ImGui::Checkbox("With Ref Color", &ref_color);
1553             if (ref_color)
1554             {
1555                 ImGui::SameLine();
1556                 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
1557             }
1558         }
1559         ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
1560         ImGui::SameLine(); HelpMarker(
1561             "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
1562             "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
1563             "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
1564         ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
1565         ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode.");
1566         ImGuiColorEditFlags flags = misc_flags;
1567         if (!alpha)            flags |= ImGuiColorEditFlags_NoAlpha;        // This is by default if you call ColorPicker3() instead of ColorPicker4()
1568         if (alpha_bar)         flags |= ImGuiColorEditFlags_AlphaBar;
1569         if (!side_preview)     flags |= ImGuiColorEditFlags_NoSidePreview;
1570         if (picker_mode == 1)  flags |= ImGuiColorEditFlags_PickerHueBar;
1571         if (picker_mode == 2)  flags |= ImGuiColorEditFlags_PickerHueWheel;
1572         if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;       // Disable all RGB/HSV/Hex displays
1573         if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB;     // Override display mode
1574         if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
1575         if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
1576         ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
1577 
1578         ImGui::Text("Set defaults in code:");
1579         ImGui::SameLine(); HelpMarker(
1580             "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
1581             "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
1582             "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
1583             "encouraging you to persistently save values that aren't forward-compatible.");
1584         if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
1585             ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
1586         if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
1587             ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
1588 
1589         // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
1590         static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
1591         ImGui::Spacing();
1592         ImGui::Text("HSV encoded colors");
1593         ImGui::SameLine(); HelpMarker(
1594             "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
1595             "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
1596             "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
1597         ImGui::Text("Color widget with InputHSV:");
1598         ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1599         ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1600         ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
1601 
1602         ImGui::TreePop();
1603     }
1604 
1605     if (ImGui::TreeNode("Drag/Slider Flags"))
1606     {
1607         // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
1608         static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
1609         ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", (unsigned int*)&flags, ImGuiSliderFlags_ClampOnInput);
1610         ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
1611         ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", (unsigned int*)&flags, ImGuiSliderFlags_Logarithmic);
1612         ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
1613         ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", (unsigned int*)&flags, ImGuiSliderFlags_NoRoundToFormat);
1614         ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
1615         ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", (unsigned int*)&flags, ImGuiSliderFlags_NoInput);
1616         ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
1617 
1618         // Drags
1619         static float drag_f = 0.5f;
1620         static int drag_i = 50;
1621         ImGui::Text("Underlying float value: %f", drag_f);
1622         ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
1623         ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
1624         ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
1625         ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
1626         ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
1627 
1628         // Sliders
1629         static float slider_f = 0.5f;
1630         static int slider_i = 50;
1631         ImGui::Text("Underlying float value: %f", slider_f);
1632         ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
1633         ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
1634 
1635         ImGui::TreePop();
1636     }
1637 
1638     if (ImGui::TreeNode("Range Widgets"))
1639     {
1640         static float begin = 10, end = 90;
1641         static int begin_i = 100, end_i = 1000;
1642         ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_ClampOnInput);
1643         ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
1644         ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
1645         ImGui::TreePop();
1646     }
1647 
1648     if (ImGui::TreeNode("Data Types"))
1649     {
1650         // DragScalar/InputScalar/SliderScalar functions allow various data types
1651         // - signed/unsigned
1652         // - 8/16/32/64-bits
1653         // - integer/float/double
1654         // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
1655         // to pass the type, and passing all arguments by pointer.
1656         // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types.
1657         // In practice, if you frequently use a given type that is not covered by the normal API entry points,
1658         // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
1659         // and then pass their address to the generic function. For example:
1660         //   bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
1661         //   {
1662         //      return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
1663         //   }
1664 
1665         // Setup limits (as helper variables so we can take their address, as explained above)
1666         // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
1667         #ifndef LLONG_MIN
1668         ImS64 LLONG_MIN = -9223372036854775807LL - 1;
1669         ImS64 LLONG_MAX = 9223372036854775807LL;
1670         ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
1671         #endif
1672         const char    s8_zero  = 0,   s8_one  = 1,   s8_fifty  = 50, s8_min  = -128,        s8_max = 127;
1673         const ImU8    u8_zero  = 0,   u8_one  = 1,   u8_fifty  = 50, u8_min  = 0,           u8_max = 255;
1674         const short   s16_zero = 0,   s16_one = 1,   s16_fifty = 50, s16_min = -32768,      s16_max = 32767;
1675         const ImU16   u16_zero = 0,   u16_one = 1,   u16_fifty = 50, u16_min = 0,           u16_max = 65535;
1676         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;
1677         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;
1678         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;
1679         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;
1680         const float   f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
1681         const double  f64_zero = 0.,  f64_one = 1.,  f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
1682 
1683         // State
1684         static char   s8_v  = 127;
1685         static ImU8   u8_v  = 255;
1686         static short  s16_v = 32767;
1687         static ImU16  u16_v = 65535;
1688         static ImS32  s32_v = -1;
1689         static ImU32  u32_v = (ImU32)-1;
1690         static ImS64  s64_v = -1;
1691         static ImU64  u64_v = (ImU64)-1;
1692         static float  f32_v = 0.123f;
1693         static double f64_v = 90000.01234567890123456789;
1694 
1695         const float drag_speed = 0.2f;
1696         static bool drag_clamp = false;
1697         ImGui::Text("Drags:");
1698         ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); HelpMarker("As with every widgets in dear imgui, we never modify values unless there is a user interaction.\nYou can override the clamping limits by using CTRL+Click to input a value.");
1699         ImGui::DragScalar("drag s8",        ImGuiDataType_S8,     &s8_v,  drag_speed, drag_clamp ? &s8_zero  : NULL, drag_clamp ? &s8_fifty  : NULL);
1700         ImGui::DragScalar("drag u8",        ImGuiDataType_U8,     &u8_v,  drag_speed, drag_clamp ? &u8_zero  : NULL, drag_clamp ? &u8_fifty  : NULL, "%u ms");
1701         ImGui::DragScalar("drag s16",       ImGuiDataType_S16,    &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
1702         ImGui::DragScalar("drag u16",       ImGuiDataType_U16,    &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
1703         ImGui::DragScalar("drag s32",       ImGuiDataType_S32,    &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
1704         ImGui::DragScalar("drag u32",       ImGuiDataType_U32,    &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
1705         ImGui::DragScalar("drag s64",       ImGuiDataType_S64,    &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
1706         ImGui::DragScalar("drag u64",       ImGuiDataType_U64,    &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
1707         ImGui::DragScalar("drag float",     ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f");
1708         ImGui::DragScalar("drag float log", ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
1709         ImGui::DragScalar("drag double",    ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL,     "%.10f grams");
1710         ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
1711 
1712         ImGui::Text("Sliders");
1713         ImGui::SliderScalar("slider s8 full",       ImGuiDataType_S8,     &s8_v,  &s8_min,   &s8_max,   "%d");
1714         ImGui::SliderScalar("slider u8 full",       ImGuiDataType_U8,     &u8_v,  &u8_min,   &u8_max,   "%u");
1715         ImGui::SliderScalar("slider s16 full",      ImGuiDataType_S16,    &s16_v, &s16_min,  &s16_max,  "%d");
1716         ImGui::SliderScalar("slider u16 full",      ImGuiDataType_U16,    &u16_v, &u16_min,  &u16_max,  "%u");
1717         ImGui::SliderScalar("slider s32 low",       ImGuiDataType_S32,    &s32_v, &s32_zero, &s32_fifty,"%d");
1718         ImGui::SliderScalar("slider s32 high",      ImGuiDataType_S32,    &s32_v, &s32_hi_a, &s32_hi_b, "%d");
1719         ImGui::SliderScalar("slider s32 full",      ImGuiDataType_S32,    &s32_v, &s32_min,  &s32_max,  "%d");
1720         ImGui::SliderScalar("slider u32 low",       ImGuiDataType_U32,    &u32_v, &u32_zero, &u32_fifty,"%u");
1721         ImGui::SliderScalar("slider u32 high",      ImGuiDataType_U32,    &u32_v, &u32_hi_a, &u32_hi_b, "%u");
1722         ImGui::SliderScalar("slider u32 full",      ImGuiDataType_U32,    &u32_v, &u32_min,  &u32_max,  "%u");
1723         ImGui::SliderScalar("slider s64 low",       ImGuiDataType_S64,    &s64_v, &s64_zero, &s64_fifty,"%I64d");
1724         ImGui::SliderScalar("slider s64 high",      ImGuiDataType_S64,    &s64_v, &s64_hi_a, &s64_hi_b, "%I64d");
1725         ImGui::SliderScalar("slider s64 full",      ImGuiDataType_S64,    &s64_v, &s64_min,  &s64_max,  "%I64d");
1726         ImGui::SliderScalar("slider u64 low",       ImGuiDataType_U64,    &u64_v, &u64_zero, &u64_fifty,"%I64u ms");
1727         ImGui::SliderScalar("slider u64 high",      ImGuiDataType_U64,    &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms");
1728         ImGui::SliderScalar("slider u64 full",      ImGuiDataType_U64,    &u64_v, &u64_min,  &u64_max,  "%I64u ms");
1729         ImGui::SliderScalar("slider float low",     ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one);
1730         ImGui::SliderScalar("slider float low log", ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
1731         ImGui::SliderScalar("slider float high",    ImGuiDataType_Float,  &f32_v, &f32_lo_a, &f32_hi_a, "%e");
1732         ImGui::SliderScalar("slider double low",    ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f grams");
1733         ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
1734         ImGui::SliderScalar("slider double high",   ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
1735 
1736         static bool inputs_step = true;
1737         ImGui::Text("Inputs");
1738         ImGui::Checkbox("Show step buttons", &inputs_step);
1739         ImGui::InputScalar("input s8",      ImGuiDataType_S8,     &s8_v,  inputs_step ? &s8_one  : NULL, NULL, "%d");
1740         ImGui::InputScalar("input u8",      ImGuiDataType_U8,     &u8_v,  inputs_step ? &u8_one  : NULL, NULL, "%u");
1741         ImGui::InputScalar("input s16",     ImGuiDataType_S16,    &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d");
1742         ImGui::InputScalar("input u16",     ImGuiDataType_U16,    &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u");
1743         ImGui::InputScalar("input s32",     ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
1744         ImGui::InputScalar("input s32 hex", ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
1745         ImGui::InputScalar("input u32",     ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
1746         ImGui::InputScalar("input u32 hex", ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
1747         ImGui::InputScalar("input s64",     ImGuiDataType_S64,    &s64_v, inputs_step ? &s64_one : NULL);
1748         ImGui::InputScalar("input u64",     ImGuiDataType_U64,    &u64_v, inputs_step ? &u64_one : NULL);
1749         ImGui::InputScalar("input float",   ImGuiDataType_Float,  &f32_v, inputs_step ? &f32_one : NULL);
1750         ImGui::InputScalar("input double",  ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL);
1751 
1752         ImGui::TreePop();
1753     }
1754 
1755     if (ImGui::TreeNode("Multi-component Widgets"))
1756     {
1757         static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
1758         static int vec4i[4] = { 1, 5, 100, 255 };
1759 
1760         ImGui::InputFloat2("input float2", vec4f);
1761         ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
1762         ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
1763         ImGui::InputInt2("input int2", vec4i);
1764         ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
1765         ImGui::SliderInt2("slider int2", vec4i, 0, 255);
1766         ImGui::Spacing();
1767 
1768         ImGui::InputFloat3("input float3", vec4f);
1769         ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
1770         ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
1771         ImGui::InputInt3("input int3", vec4i);
1772         ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
1773         ImGui::SliderInt3("slider int3", vec4i, 0, 255);
1774         ImGui::Spacing();
1775 
1776         ImGui::InputFloat4("input float4", vec4f);
1777         ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
1778         ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
1779         ImGui::InputInt4("input int4", vec4i);
1780         ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
1781         ImGui::SliderInt4("slider int4", vec4i, 0, 255);
1782 
1783         ImGui::TreePop();
1784     }
1785 
1786     if (ImGui::TreeNode("Vertical Sliders"))
1787     {
1788         const float spacing = 4;
1789         ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1790 
1791         static int int_value = 0;
1792         ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
1793         ImGui::SameLine();
1794 
1795         static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
1796         ImGui::PushID("set1");
1797         for (int i = 0; i < 7; i++)
1798         {
1799             if (i > 0) ImGui::SameLine();
1800             ImGui::PushID(i);
1801             ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
1802             ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
1803             ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
1804             ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
1805             ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
1806             if (ImGui::IsItemActive() || ImGui::IsItemHovered())
1807                 ImGui::SetTooltip("%.3f", values[i]);
1808             ImGui::PopStyleColor(4);
1809             ImGui::PopID();
1810         }
1811         ImGui::PopID();
1812 
1813         ImGui::SameLine();
1814         ImGui::PushID("set2");
1815         static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
1816         const int rows = 3;
1817         const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
1818         for (int nx = 0; nx < 4; nx++)
1819         {
1820             if (nx > 0) ImGui::SameLine();
1821             ImGui::BeginGroup();
1822             for (int ny = 0; ny < rows; ny++)
1823             {
1824                 ImGui::PushID(nx * rows + ny);
1825                 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
1826                 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
1827                     ImGui::SetTooltip("%.3f", values2[nx]);
1828                 ImGui::PopID();
1829             }
1830             ImGui::EndGroup();
1831         }
1832         ImGui::PopID();
1833 
1834         ImGui::SameLine();
1835         ImGui::PushID("set3");
1836         for (int i = 0; i < 4; i++)
1837         {
1838             if (i > 0) ImGui::SameLine();
1839             ImGui::PushID(i);
1840             ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
1841             ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
1842             ImGui::PopStyleVar();
1843             ImGui::PopID();
1844         }
1845         ImGui::PopID();
1846         ImGui::PopStyleVar();
1847         ImGui::TreePop();
1848     }
1849 
1850     if (ImGui::TreeNode("Drag and Drop"))
1851     {
1852         if (ImGui::TreeNode("Drag and drop in standard widgets"))
1853         {
1854             // ColorEdit widgets automatically act as drag source and drag target.
1855             // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
1856             // to allow your own widgets to use colors in their drag and drop interaction.
1857             // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
1858             HelpMarker("You can drag from the colored squares.");
1859             static float col1[3] = { 1.0f, 0.0f, 0.2f };
1860             static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
1861             ImGui::ColorEdit3("color 1", col1);
1862             ImGui::ColorEdit4("color 2", col2);
1863             ImGui::TreePop();
1864         }
1865 
1866         if (ImGui::TreeNode("Drag and drop to copy/swap items"))
1867         {
1868             enum Mode
1869             {
1870                 Mode_Copy,
1871                 Mode_Move,
1872                 Mode_Swap
1873             };
1874             static int mode = 0;
1875             if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
1876             if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
1877             if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
1878             static const char* names[9] =
1879             {
1880                 "Bobby", "Beatrice", "Betty",
1881                 "Brianna", "Barry", "Bernard",
1882                 "Bibi", "Blaine", "Bryn"
1883             };
1884             for (int n = 0; n < IM_ARRAYSIZE(names); n++)
1885             {
1886                 ImGui::PushID(n);
1887                 if ((n % 3) != 0)
1888                     ImGui::SameLine();
1889                 ImGui::Button(names[n], ImVec2(60, 60));
1890 
1891                 // Our buttons are both drag sources and drag targets here!
1892                 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
1893                 {
1894                     // Set payload to carry the index of our item (could be anything)
1895                     ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
1896 
1897                     // Display preview (could be anything, e.g. when dragging an image we could decide to display
1898                     // the filename and a small preview of the image, etc.)
1899                     if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
1900                     if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
1901                     if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
1902                     ImGui::EndDragDropSource();
1903                 }
1904                 if (ImGui::BeginDragDropTarget())
1905                 {
1906                     if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
1907                     {
1908                         IM_ASSERT(payload->DataSize == sizeof(int));
1909                         int payload_n = *(const int*)payload->Data;
1910                         if (mode == Mode_Copy)
1911                         {
1912                             names[n] = names[payload_n];
1913                         }
1914                         if (mode == Mode_Move)
1915                         {
1916                             names[n] = names[payload_n];
1917                             names[payload_n] = "";
1918                         }
1919                         if (mode == Mode_Swap)
1920                         {
1921                             const char* tmp = names[n];
1922                             names[n] = names[payload_n];
1923                             names[payload_n] = tmp;
1924                         }
1925                     }
1926                     ImGui::EndDragDropTarget();
1927                 }
1928                 ImGui::PopID();
1929             }
1930             ImGui::TreePop();
1931         }
1932 
1933         if (ImGui::TreeNode("Drag to reorder items (simple)"))
1934         {
1935             // Simple reordering
1936             HelpMarker(
1937                 "We don't use the drag and drop api at all here! "
1938                 "Instead we query when the item is held but not hovered, and order items accordingly.");
1939             static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
1940             for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
1941             {
1942                 const char* item = item_names[n];
1943                 ImGui::Selectable(item);
1944 
1945                 if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
1946                 {
1947                     int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
1948                     if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
1949                     {
1950                         item_names[n] = item_names[n_next];
1951                         item_names[n_next] = item;
1952                         ImGui::ResetMouseDragDelta();
1953                     }
1954                 }
1955             }
1956             ImGui::TreePop();
1957         }
1958 
1959         ImGui::TreePop();
1960     }
1961 
1962     if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)"))
1963     {
1964         // Select an item type
1965         const char* item_names[] =
1966         {
1967             "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat",
1968             "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "ListBox"
1969         };
1970         static int item_type = 1;
1971         ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
1972         ImGui::SameLine();
1973         HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions.");
1974 
1975         // Submit selected item item so we can query their status in the code following it.
1976         bool ret = false;
1977         static bool b = false;
1978         static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
1979         static char str[16] = {};
1980         if (item_type == 0) { ImGui::Text("ITEM: Text"); }                                              // Testing text items with no identifier/interaction
1981         if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); }                                    // Testing button
1982         if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
1983         if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); }                            // Testing checkbox
1984         if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); }   // Testing basic item
1985         if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); }  // Testing input text (which handles tabbing)
1986         if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); }               // Testing +/- buttons on scalar input
1987         if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); }                   // Testing multi-component items (IsItemXXX flags are reported merged)
1988         if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); }                     // Testing multi-component items (IsItemXXX flags are reported merged)
1989         if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); }                                // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
1990         if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); }     // Testing tree node
1991         if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
1992         if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
1993 
1994         // Display the values of IsItemHovered() and other common item state functions.
1995         // Note that the ImGuiHoveredFlags_XXX flags can be combined.
1996         // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
1997         // we query every state in a single call to avoid storing them and to simplify the code.
1998         ImGui::BulletText(
1999             "Return value = %d\n"
2000             "IsItemFocused() = %d\n"
2001             "IsItemHovered() = %d\n"
2002             "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2003             "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2004             "IsItemHovered(_AllowWhenOverlapped) = %d\n"
2005             "IsItemHovered(_RectOnly) = %d\n"
2006             "IsItemActive() = %d\n"
2007             "IsItemEdited() = %d\n"
2008             "IsItemActivated() = %d\n"
2009             "IsItemDeactivated() = %d\n"
2010             "IsItemDeactivatedAfterEdit() = %d\n"
2011             "IsItemVisible() = %d\n"
2012             "IsItemClicked() = %d\n"
2013             "IsItemToggledOpen() = %d\n"
2014             "GetItemRectMin() = (%.1f, %.1f)\n"
2015             "GetItemRectMax() = (%.1f, %.1f)\n"
2016             "GetItemRectSize() = (%.1f, %.1f)",
2017             ret,
2018             ImGui::IsItemFocused(),
2019             ImGui::IsItemHovered(),
2020             ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2021             ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2022             ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped),
2023             ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2024             ImGui::IsItemActive(),
2025             ImGui::IsItemEdited(),
2026             ImGui::IsItemActivated(),
2027             ImGui::IsItemDeactivated(),
2028             ImGui::IsItemDeactivatedAfterEdit(),
2029             ImGui::IsItemVisible(),
2030             ImGui::IsItemClicked(),
2031             ImGui::IsItemToggledOpen(),
2032             ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2033             ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2034             ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2035         );
2036 
2037         static bool embed_all_inside_a_child_window = false;
2038         ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window);
2039         if (embed_all_inside_a_child_window)
2040             ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true);
2041 
2042         // Testing IsWindowFocused() function with its various flags.
2043         // Note that the ImGuiFocusedFlags_XXX flags can be combined.
2044         ImGui::BulletText(
2045             "IsWindowFocused() = %d\n"
2046             "IsWindowFocused(_ChildWindows) = %d\n"
2047             "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2048             "IsWindowFocused(_RootWindow) = %d\n"
2049             "IsWindowFocused(_AnyWindow) = %d\n",
2050             ImGui::IsWindowFocused(),
2051             ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2052             ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2053             ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2054             ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2055 
2056         // Testing IsWindowHovered() function with its various flags.
2057         // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2058         ImGui::BulletText(
2059             "IsWindowHovered() = %d\n"
2060             "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2061             "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2062             "IsWindowHovered(_ChildWindows) = %d\n"
2063             "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2064             "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2065             "IsWindowHovered(_RootWindow) = %d\n"
2066             "IsWindowHovered(_AnyWindow) = %d\n",
2067             ImGui::IsWindowHovered(),
2068             ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2069             ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2070             ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2071             ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2072             ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2073             ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2074             ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));
2075 
2076         ImGui::BeginChild("child", ImVec2(0, 50), true);
2077         ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2078         ImGui::EndChild();
2079         if (embed_all_inside_a_child_window)
2080             ImGui::EndChild();
2081 
2082         static char unused_str[] = "This widget is only here to be able to tab-out of the widgets above.";
2083         ImGui::InputText("unused", unused_str, IM_ARRAYSIZE(unused_str), ImGuiInputTextFlags_ReadOnly);
2084 
2085         // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2086         // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2087         // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2088         static bool test_window = false;
2089         ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2090         if (test_window)
2091         {
2092             // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2093             // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2094             ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2095             if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2096             {
2097                 if (ImGui::MenuItem("Close")) { test_window = false; }
2098                 ImGui::EndPopup();
2099             }
2100             ImGui::Text(
2101                 "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2102                 "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2103                 ImGui::IsItemHovered(), ImGui::IsItemActive());
2104             ImGui::End();
2105         }
2106 
2107         ImGui::TreePop();
2108     }
2109 }
2110 
ShowDemoWindowLayout()2111 static void ShowDemoWindowLayout()
2112 {
2113     if (!ImGui::CollapsingHeader("Layout & Scrolling"))
2114         return;
2115 
2116     if (ImGui::TreeNode("Child windows"))
2117     {
2118         HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
2119         static bool disable_mouse_wheel = false;
2120         static bool disable_menu = false;
2121         ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
2122         ImGui::Checkbox("Disable Menu", &disable_menu);
2123 
2124         // Child 1: no border, enable horizontal scrollbar
2125         {
2126             ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
2127             if (disable_mouse_wheel)
2128                 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2129             ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags);
2130             for (int i = 0; i < 100; i++)
2131                 ImGui::Text("%04d: scrollable region", i);
2132             ImGui::EndChild();
2133         }
2134 
2135         ImGui::SameLine();
2136 
2137         // Child 2: rounded border
2138         {
2139             ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
2140             if (disable_mouse_wheel)
2141                 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2142             if (!disable_menu)
2143                 window_flags |= ImGuiWindowFlags_MenuBar;
2144             ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
2145             ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags);
2146             if (!disable_menu && ImGui::BeginMenuBar())
2147             {
2148                 if (ImGui::BeginMenu("Menu"))
2149                 {
2150                     ShowExampleMenuFile();
2151                     ImGui::EndMenu();
2152                 }
2153                 ImGui::EndMenuBar();
2154             }
2155             ImGui::Columns(2);
2156             for (int i = 0; i < 100; i++)
2157             {
2158                 char buf[32];
2159                 sprintf(buf, "%03d", i);
2160                 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
2161                 ImGui::NextColumn();
2162             }
2163             ImGui::EndChild();
2164             ImGui::PopStyleVar();
2165         }
2166 
2167         ImGui::Separator();
2168 
2169         // Demonstrate a few extra things
2170         // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
2171         // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
2172         //   You can also call SetNextWindowPos() to position the child window. The parent window will effectively
2173         //   layout from this position.
2174         // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
2175         //   the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details.
2176         {
2177             static int offset_x = 0;
2178             ImGui::SetNextItemWidth(100);
2179             ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
2180 
2181             ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
2182             ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
2183             ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None);
2184             for (int n = 0; n < 50; n++)
2185                 ImGui::Text("Some test %d", n);
2186             ImGui::EndChild();
2187             bool child_is_hovered = ImGui::IsItemHovered();
2188             ImVec2 child_rect_min = ImGui::GetItemRectMin();
2189             ImVec2 child_rect_max = ImGui::GetItemRectMax();
2190             ImGui::PopStyleColor();
2191             ImGui::Text("Hovered: %d", child_is_hovered);
2192             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);
2193         }
2194 
2195         ImGui::TreePop();
2196     }
2197 
2198     if (ImGui::TreeNode("Widgets Width"))
2199     {
2200         // Use SetNextItemWidth() to set the width of a single upcoming item.
2201         // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
2202         // In real code use you'll probably want to choose width values that are proportional to your font size
2203         // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
2204 
2205         static float f = 0.0f;
2206         ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
2207         ImGui::SameLine(); HelpMarker("Fixed width.");
2208         ImGui::SetNextItemWidth(100);
2209         ImGui::DragFloat("float##1", &f);
2210 
2211         ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)");
2212         ImGui::SameLine(); HelpMarker("Half of window width.");
2213         ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f);
2214         ImGui::DragFloat("float##2", &f);
2215 
2216         ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
2217         ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
2218         ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
2219         ImGui::DragFloat("float##3", &f);
2220 
2221         ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
2222         ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
2223         ImGui::SetNextItemWidth(-100);
2224         ImGui::DragFloat("float##4", &f);
2225 
2226         // Demonstrate using PushItemWidth to surround three items.
2227         // Calling SetNextItemWidth() before each of them would have the same effect.
2228         ImGui::Text("SetNextItemWidth/PushItemWidth(-1)");
2229         ImGui::SameLine(); HelpMarker("Align to right edge");
2230         ImGui::PushItemWidth(-1);
2231         ImGui::DragFloat("##float5a", &f);
2232         ImGui::DragFloat("##float5b", &f);
2233         ImGui::DragFloat("##float5c", &f);
2234         ImGui::PopItemWidth();
2235 
2236         ImGui::TreePop();
2237     }
2238 
2239     if (ImGui::TreeNode("Basic Horizontal Layout"))
2240     {
2241         ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
2242 
2243         // Text
2244         ImGui::Text("Two items: Hello"); ImGui::SameLine();
2245         ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
2246 
2247         // Adjust spacing
2248         ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
2249         ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
2250 
2251         // Button
2252         ImGui::AlignTextToFramePadding();
2253         ImGui::Text("Normal buttons"); ImGui::SameLine();
2254         ImGui::Button("Banana"); ImGui::SameLine();
2255         ImGui::Button("Apple"); ImGui::SameLine();
2256         ImGui::Button("Corniflower");
2257 
2258         // Button
2259         ImGui::Text("Small buttons"); ImGui::SameLine();
2260         ImGui::SmallButton("Like this one"); ImGui::SameLine();
2261         ImGui::Text("can fit within a text block.");
2262 
2263         // Aligned to arbitrary position. Easy/cheap column.
2264         ImGui::Text("Aligned");
2265         ImGui::SameLine(150); ImGui::Text("x=150");
2266         ImGui::SameLine(300); ImGui::Text("x=300");
2267         ImGui::Text("Aligned");
2268         ImGui::SameLine(150); ImGui::SmallButton("x=150");
2269         ImGui::SameLine(300); ImGui::SmallButton("x=300");
2270 
2271         // Checkbox
2272         static bool c1 = false, c2 = false, c3 = false, c4 = false;
2273         ImGui::Checkbox("My", &c1); ImGui::SameLine();
2274         ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
2275         ImGui::Checkbox("Is", &c3); ImGui::SameLine();
2276         ImGui::Checkbox("Rich", &c4);
2277 
2278         // Various
2279         static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
2280         ImGui::PushItemWidth(80);
2281         const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
2282         static int item = -1;
2283         ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
2284         ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
2285         ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
2286         ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
2287         ImGui::PopItemWidth();
2288 
2289         ImGui::PushItemWidth(80);
2290         ImGui::Text("Lists:");
2291         static int selection[4] = { 0, 1, 2, 3 };
2292         for (int i = 0; i < 4; i++)
2293         {
2294             if (i > 0) ImGui::SameLine();
2295             ImGui::PushID(i);
2296             ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
2297             ImGui::PopID();
2298             //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i);
2299         }
2300         ImGui::PopItemWidth();
2301 
2302         // Dummy
2303         ImVec2 button_sz(40, 40);
2304         ImGui::Button("A", button_sz); ImGui::SameLine();
2305         ImGui::Dummy(button_sz); ImGui::SameLine();
2306         ImGui::Button("B", button_sz);
2307 
2308         // Manually wrapping
2309         // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
2310         ImGui::Text("Manually wrapping:");
2311         ImGuiStyle& style = ImGui::GetStyle();
2312         int buttons_count = 20;
2313         float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
2314         for (int n = 0; n < buttons_count; n++)
2315         {
2316             ImGui::PushID(n);
2317             ImGui::Button("Box", button_sz);
2318             float last_button_x2 = ImGui::GetItemRectMax().x;
2319             float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
2320             if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
2321                 ImGui::SameLine();
2322             ImGui::PopID();
2323         }
2324 
2325         ImGui::TreePop();
2326     }
2327 
2328     if (ImGui::TreeNode("Tabs"))
2329     {
2330         if (ImGui::TreeNode("Basic"))
2331         {
2332             ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
2333             if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
2334             {
2335                 if (ImGui::BeginTabItem("Avocado"))
2336                 {
2337                     ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
2338                     ImGui::EndTabItem();
2339                 }
2340                 if (ImGui::BeginTabItem("Broccoli"))
2341                 {
2342                     ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
2343                     ImGui::EndTabItem();
2344                 }
2345                 if (ImGui::BeginTabItem("Cucumber"))
2346                 {
2347                     ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
2348                     ImGui::EndTabItem();
2349                 }
2350                 ImGui::EndTabBar();
2351             }
2352             ImGui::Separator();
2353             ImGui::TreePop();
2354         }
2355 
2356         if (ImGui::TreeNode("Advanced & Close Button"))
2357         {
2358             // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
2359             static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
2360             ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable);
2361             ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
2362             ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
2363             ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
2364             if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
2365                 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
2366             if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
2367                 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
2368             if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
2369                 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
2370 
2371             // Tab Bar
2372             const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
2373             static bool opened[4] = { true, true, true, true }; // Persistent user state
2374             for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
2375             {
2376                 if (n > 0) { ImGui::SameLine(); }
2377                 ImGui::Checkbox(names[n], &opened[n]);
2378             }
2379 
2380             // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
2381             // the underlying bool will be set to false when the tab is closed.
2382             if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
2383             {
2384                 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
2385                     if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
2386                     {
2387                         ImGui::Text("This is the %s tab!", names[n]);
2388                         if (n & 1)
2389                             ImGui::Text("I am an odd tab.");
2390                         ImGui::EndTabItem();
2391                     }
2392                 ImGui::EndTabBar();
2393             }
2394             ImGui::Separator();
2395             ImGui::TreePop();
2396         }
2397         ImGui::TreePop();
2398     }
2399 
2400     if (ImGui::TreeNode("Groups"))
2401     {
2402         HelpMarker(
2403             "BeginGroup() basically locks the horizontal position for new line. "
2404             "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
2405             "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
2406         ImGui::BeginGroup();
2407         {
2408             ImGui::BeginGroup();
2409             ImGui::Button("AAA");
2410             ImGui::SameLine();
2411             ImGui::Button("BBB");
2412             ImGui::SameLine();
2413             ImGui::BeginGroup();
2414             ImGui::Button("CCC");
2415             ImGui::Button("DDD");
2416             ImGui::EndGroup();
2417             ImGui::SameLine();
2418             ImGui::Button("EEE");
2419             ImGui::EndGroup();
2420             if (ImGui::IsItemHovered())
2421                 ImGui::SetTooltip("First group hovered");
2422         }
2423         // Capture the group size and create widgets using the same size
2424         ImVec2 size = ImGui::GetItemRectSize();
2425         const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
2426         ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
2427 
2428         ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
2429         ImGui::SameLine();
2430         ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
2431         ImGui::EndGroup();
2432         ImGui::SameLine();
2433 
2434         ImGui::Button("LEVERAGE\nBUZZWORD", size);
2435         ImGui::SameLine();
2436 
2437         if (ImGui::ListBoxHeader("List", size))
2438         {
2439             ImGui::Selectable("Selected", true);
2440             ImGui::Selectable("Not Selected", false);
2441             ImGui::ListBoxFooter();
2442         }
2443 
2444         ImGui::TreePop();
2445     }
2446 
2447     if (ImGui::TreeNode("Text Baseline Alignment"))
2448     {
2449         {
2450             ImGui::BulletText("Text baseline:");
2451             ImGui::SameLine(); HelpMarker(
2452                 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
2453                 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
2454             ImGui::Indent();
2455 
2456             ImGui::Text("KO Blahblah"); ImGui::SameLine();
2457             ImGui::Button("Some framed item"); ImGui::SameLine();
2458             HelpMarker("Baseline of button will look misaligned with text..");
2459 
2460             // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
2461             // (because we don't know what's coming after the Text() statement, we need to move the text baseline
2462             // down by FramePadding.y ahead of time)
2463             ImGui::AlignTextToFramePadding();
2464             ImGui::Text("OK Blahblah"); ImGui::SameLine();
2465             ImGui::Button("Some framed item"); ImGui::SameLine();
2466             HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
2467 
2468             // SmallButton() uses the same vertical padding as Text
2469             ImGui::Button("TEST##1"); ImGui::SameLine();
2470             ImGui::Text("TEST"); ImGui::SameLine();
2471             ImGui::SmallButton("TEST##2");
2472 
2473             // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
2474             ImGui::AlignTextToFramePadding();
2475             ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
2476             ImGui::Button("Item##1"); ImGui::SameLine();
2477             ImGui::Text("Item"); ImGui::SameLine();
2478             ImGui::SmallButton("Item##2"); ImGui::SameLine();
2479             ImGui::Button("Item##3");
2480 
2481             ImGui::Unindent();
2482         }
2483 
2484         ImGui::Spacing();
2485 
2486         {
2487             ImGui::BulletText("Multi-line text:");
2488             ImGui::Indent();
2489             ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
2490             ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2491             ImGui::Text("Banana");
2492 
2493             ImGui::Text("Banana"); ImGui::SameLine();
2494             ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2495             ImGui::Text("One\nTwo\nThree");
2496 
2497             ImGui::Button("HOP##1"); ImGui::SameLine();
2498             ImGui::Text("Banana"); ImGui::SameLine();
2499             ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2500             ImGui::Text("Banana");
2501 
2502             ImGui::Button("HOP##2"); ImGui::SameLine();
2503             ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2504             ImGui::Text("Banana");
2505             ImGui::Unindent();
2506         }
2507 
2508         ImGui::Spacing();
2509 
2510         {
2511             ImGui::BulletText("Misc items:");
2512             ImGui::Indent();
2513 
2514             // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
2515             ImGui::Button("80x80", ImVec2(80, 80));
2516             ImGui::SameLine();
2517             ImGui::Button("50x50", ImVec2(50, 50));
2518             ImGui::SameLine();
2519             ImGui::Button("Button()");
2520             ImGui::SameLine();
2521             ImGui::SmallButton("SmallButton()");
2522 
2523             // Tree
2524             const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
2525             ImGui::Button("Button##1");
2526             ImGui::SameLine(0.0f, spacing);
2527             if (ImGui::TreeNode("Node##1"))
2528             {
2529                 // Placeholder tree data
2530                 for (int i = 0; i < 6; i++)
2531                     ImGui::BulletText("Item %d..", i);
2532                 ImGui::TreePop();
2533             }
2534 
2535             // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
2536             // Otherwise you can use SmallButton() (smaller fit).
2537             ImGui::AlignTextToFramePadding();
2538 
2539             // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
2540             // other contents below the node.
2541             bool node_open = ImGui::TreeNode("Node##2");
2542             ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
2543             if (node_open)
2544             {
2545                 // Placeholder tree data
2546                 for (int i = 0; i < 6; i++)
2547                     ImGui::BulletText("Item %d..", i);
2548                 ImGui::TreePop();
2549             }
2550 
2551             // Bullet
2552             ImGui::Button("Button##3");
2553             ImGui::SameLine(0.0f, spacing);
2554             ImGui::BulletText("Bullet text");
2555 
2556             ImGui::AlignTextToFramePadding();
2557             ImGui::BulletText("Node");
2558             ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
2559             ImGui::Unindent();
2560         }
2561 
2562         ImGui::TreePop();
2563     }
2564 
2565     if (ImGui::TreeNode("Scrolling"))
2566     {
2567         // Vertical scroll functions
2568         HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
2569 
2570         static int track_item = 50;
2571         static bool enable_track = true;
2572         static bool enable_extra_decorations = false;
2573         static float scroll_to_off_px = 0.0f;
2574         static float scroll_to_pos_px = 200.0f;
2575 
2576         ImGui::Checkbox("Decoration", &enable_extra_decorations);
2577 
2578         ImGui::Checkbox("Track", &enable_track);
2579         ImGui::PushItemWidth(100);
2580         ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
2581 
2582         bool scroll_to_off = ImGui::Button("Scroll Offset");
2583         ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
2584 
2585         bool scroll_to_pos = ImGui::Button("Scroll To Pos");
2586         ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
2587         ImGui::PopItemWidth();
2588 
2589         if (scroll_to_off || scroll_to_pos)
2590             enable_track = false;
2591 
2592         ImGuiStyle& style = ImGui::GetStyle();
2593         float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
2594         if (child_w < 1.0f)
2595             child_w = 1.0f;
2596         ImGui::PushID("##VerticalScrolling");
2597         for (int i = 0; i < 5; i++)
2598         {
2599             if (i > 0) ImGui::SameLine();
2600             ImGui::BeginGroup();
2601             const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
2602             ImGui::TextUnformatted(names[i]);
2603 
2604             const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
2605             const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
2606             const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags);
2607             if (ImGui::BeginMenuBar())
2608             {
2609                 ImGui::TextUnformatted("abc");
2610                 ImGui::EndMenuBar();
2611             }
2612             if (scroll_to_off)
2613                 ImGui::SetScrollY(scroll_to_off_px);
2614             if (scroll_to_pos)
2615                 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
2616             if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
2617             {
2618                 for (int item = 0; item < 100; item++)
2619                 {
2620                     if (enable_track && item == track_item)
2621                     {
2622                         ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
2623                         ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
2624                     }
2625                     else
2626                     {
2627                         ImGui::Text("Item %d", item);
2628                     }
2629                 }
2630             }
2631             float scroll_y = ImGui::GetScrollY();
2632             float scroll_max_y = ImGui::GetScrollMaxY();
2633             ImGui::EndChild();
2634             ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
2635             ImGui::EndGroup();
2636         }
2637         ImGui::PopID();
2638 
2639         // Horizontal scroll functions
2640         ImGui::Spacing();
2641         HelpMarker(
2642             "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
2643             "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
2644             "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
2645             "equivalent SetScrollFromPosY(+1) wouldn't.");
2646         ImGui::PushID("##HorizontalScrolling");
2647         for (int i = 0; i < 5; i++)
2648         {
2649             float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
2650             ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
2651             ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
2652             bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags);
2653             if (scroll_to_off)
2654                 ImGui::SetScrollX(scroll_to_off_px);
2655             if (scroll_to_pos)
2656                 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
2657             if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
2658             {
2659                 for (int item = 0; item < 100; item++)
2660                 {
2661                     if (enable_track && item == track_item)
2662                     {
2663                         ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
2664                         ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
2665                     }
2666                     else
2667                     {
2668                         ImGui::Text("Item %d", item);
2669                     }
2670                     ImGui::SameLine();
2671                 }
2672             }
2673             float scroll_x = ImGui::GetScrollX();
2674             float scroll_max_x = ImGui::GetScrollMaxX();
2675             ImGui::EndChild();
2676             ImGui::SameLine();
2677             const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
2678             ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
2679             ImGui::Spacing();
2680         }
2681         ImGui::PopID();
2682 
2683         // Miscellaneous Horizontal Scrolling Demo
2684         HelpMarker(
2685             "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
2686             "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
2687         static int lines = 7;
2688         ImGui::SliderInt("Lines", &lines, 1, 15);
2689         ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
2690         ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
2691         ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
2692         ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar);
2693         for (int line = 0; line < lines; line++)
2694         {
2695             // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
2696             // If you want to create your own time line for a real application you may be better off manipulating
2697             // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
2698             // yourself. You may also want to use the lower-level ImDrawList API.
2699             int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
2700             for (int n = 0; n < num_buttons; n++)
2701             {
2702                 if (n > 0) ImGui::SameLine();
2703                 ImGui::PushID(n + line * 1000);
2704                 char num_buf[16];
2705                 sprintf(num_buf, "%d", n);
2706                 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
2707                 float hue = n * 0.05f;
2708                 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
2709                 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
2710                 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
2711                 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
2712                 ImGui::PopStyleColor(3);
2713                 ImGui::PopID();
2714             }
2715         }
2716         float scroll_x = ImGui::GetScrollX();
2717         float scroll_max_x = ImGui::GetScrollMaxX();
2718         ImGui::EndChild();
2719         ImGui::PopStyleVar(2);
2720         float scroll_x_delta = 0.0f;
2721         ImGui::SmallButton("<<");
2722         if (ImGui::IsItemActive())
2723             scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
2724         ImGui::SameLine();
2725         ImGui::Text("Scroll from code"); ImGui::SameLine();
2726         ImGui::SmallButton(">>");
2727         if (ImGui::IsItemActive())
2728             scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
2729         ImGui::SameLine();
2730         ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
2731         if (scroll_x_delta != 0.0f)
2732         {
2733             // Demonstrate a trick: you can use Begin to set yourself in the context of another window
2734             // (here we are already out of your child window)
2735             ImGui::BeginChild("scrolling");
2736             ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
2737             ImGui::EndChild();
2738         }
2739         ImGui::Spacing();
2740 
2741         static bool show_horizontal_contents_size_demo_window = false;
2742         ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
2743 
2744         if (show_horizontal_contents_size_demo_window)
2745         {
2746             static bool show_h_scrollbar = true;
2747             static bool show_button = true;
2748             static bool show_tree_nodes = true;
2749             static bool show_text_wrapped = false;
2750             static bool show_columns = true;
2751             static bool show_tab_bar = true;
2752             static bool show_child = false;
2753             static bool explicit_content_size = false;
2754             static float contents_size_x = 300.0f;
2755             if (explicit_content_size)
2756                 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
2757             ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
2758             ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
2759             ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
2760             HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
2761             ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
2762             ImGui::Checkbox("Button", &show_button);            // Will grow contents size (unless explicitly overwritten)
2763             ImGui::Checkbox("Tree nodes", &show_tree_nodes);    // Will grow contents size and display highlight over full width
2764             ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
2765             ImGui::Checkbox("Columns", &show_columns);          // Will use contents size
2766             ImGui::Checkbox("Tab bar", &show_tab_bar);          // Will use contents size
2767             ImGui::Checkbox("Child", &show_child);              // Will grow and use contents size
2768             ImGui::Checkbox("Explicit content size", &explicit_content_size);
2769             ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
2770             if (explicit_content_size)
2771             {
2772                 ImGui::SameLine();
2773                 ImGui::SetNextItemWidth(100);
2774                 ImGui::DragFloat("##csx", &contents_size_x);
2775                 ImVec2 p = ImGui::GetCursorScreenPos();
2776                 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
2777                 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
2778                 ImGui::Dummy(ImVec2(0, 10));
2779             }
2780             ImGui::PopStyleVar(2);
2781             ImGui::Separator();
2782             if (show_button)
2783             {
2784                 ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
2785             }
2786             if (show_tree_nodes)
2787             {
2788                 bool open = true;
2789                 if (ImGui::TreeNode("this is a tree node"))
2790                 {
2791                     if (ImGui::TreeNode("another one of those tree node..."))
2792                     {
2793                         ImGui::Text("Some tree contents");
2794                         ImGui::TreePop();
2795                     }
2796                     ImGui::TreePop();
2797                 }
2798                 ImGui::CollapsingHeader("CollapsingHeader", &open);
2799             }
2800             if (show_text_wrapped)
2801             {
2802                 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
2803             }
2804             if (show_columns)
2805             {
2806                 ImGui::Columns(4);
2807                 for (int n = 0; n < 4; n++)
2808                 {
2809                     ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
2810                     ImGui::NextColumn();
2811                 }
2812                 ImGui::Columns(1);
2813             }
2814             if (show_tab_bar && ImGui::BeginTabBar("Hello"))
2815             {
2816                 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
2817                 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
2818                 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
2819                 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
2820                 ImGui::EndTabBar();
2821             }
2822             if (show_child)
2823             {
2824                 ImGui::BeginChild("child", ImVec2(0, 0), true);
2825                 ImGui::EndChild();
2826             }
2827             ImGui::End();
2828         }
2829 
2830         ImGui::TreePop();
2831     }
2832 
2833     if (ImGui::TreeNode("Clipping"))
2834     {
2835         static ImVec2 size(100.0f, 100.0f);
2836         static ImVec2 offset(30.0f, 30.0f);
2837         ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
2838         ImGui::TextWrapped("(Click and drag to scroll)");
2839 
2840         for (int n = 0; n < 3; n++)
2841         {
2842             if (n > 0)
2843                 ImGui::SameLine();
2844             ImGui::PushID(n);
2845             ImGui::BeginGroup(); // Lock X position
2846 
2847             ImGui::InvisibleButton("##empty", size);
2848             if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
2849             {
2850                 offset.x += ImGui::GetIO().MouseDelta.x;
2851                 offset.y += ImGui::GetIO().MouseDelta.y;
2852             }
2853             const ImVec2 p0 = ImGui::GetItemRectMin();
2854             const ImVec2 p1 = ImGui::GetItemRectMax();
2855             const char* text_str = "Line 1 hello\nLine 2 clip me!";
2856             const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
2857             ImDrawList* draw_list = ImGui::GetWindowDrawList();
2858 
2859             switch (n)
2860             {
2861             case 0:
2862                 HelpMarker(
2863                     "Using ImGui::PushClipRect():\n"
2864                     "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
2865                     "(use this if you want your clipping rectangle to affect interactions)");
2866                 ImGui::PushClipRect(p0, p1, true);
2867                 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
2868                 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
2869                 ImGui::PopClipRect();
2870                 break;
2871             case 1:
2872                 HelpMarker(
2873                     "Using ImDrawList::PushClipRect():\n"
2874                     "Will alter ImDrawList rendering only.\n"
2875                     "(use this as a shortcut if you are only using ImDrawList calls)");
2876                 draw_list->PushClipRect(p0, p1, true);
2877                 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
2878                 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
2879                 draw_list->PopClipRect();
2880                 break;
2881             case 2:
2882                 HelpMarker(
2883                     "Using ImDrawList::AddText() with a fine ClipRect:\n"
2884                     "Will alter only this specific ImDrawList::AddText() rendering.\n"
2885                     "(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)");
2886                 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
2887                 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
2888                 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
2889                 break;
2890             }
2891             ImGui::EndGroup();
2892             ImGui::PopID();
2893         }
2894 
2895         ImGui::TreePop();
2896     }
2897 }
2898 
ShowDemoWindowPopups()2899 static void ShowDemoWindowPopups()
2900 {
2901     if (!ImGui::CollapsingHeader("Popups & Modal windows"))
2902         return;
2903 
2904     // The properties of popups windows are:
2905     // - They block normal mouse hovering detection outside them. (*)
2906     // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
2907     // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
2908     //   we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
2909     // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
2910     //     when normally blocked by a popup.
2911     // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
2912     // popups at any time.
2913 
2914     // Typical use for regular windows:
2915     //   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();
2916     // Typical use for popups:
2917     //   if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
2918 
2919     // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
2920     // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
2921 
2922     if (ImGui::TreeNode("Popups"))
2923     {
2924         ImGui::TextWrapped(
2925             "When a popup is active, it inhibits interacting with windows that are behind the popup. "
2926             "Clicking outside the popup closes it.");
2927 
2928         static int selected_fish = -1;
2929         const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
2930         static bool toggles[] = { true, false, false, false, false };
2931 
2932         // Simple selection popup (if you want to show the current selection inside the Button itself,
2933         // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
2934         if (ImGui::Button("Select.."))
2935             ImGui::OpenPopup("my_select_popup");
2936         ImGui::SameLine();
2937         ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
2938         if (ImGui::BeginPopup("my_select_popup"))
2939         {
2940             ImGui::Text("Aquarium");
2941             ImGui::Separator();
2942             for (int i = 0; i < IM_ARRAYSIZE(names); i++)
2943                 if (ImGui::Selectable(names[i]))
2944                     selected_fish = i;
2945             ImGui::EndPopup();
2946         }
2947 
2948         // Showing a menu with toggles
2949         if (ImGui::Button("Toggle.."))
2950             ImGui::OpenPopup("my_toggle_popup");
2951         if (ImGui::BeginPopup("my_toggle_popup"))
2952         {
2953             for (int i = 0; i < IM_ARRAYSIZE(names); i++)
2954                 ImGui::MenuItem(names[i], "", &toggles[i]);
2955             if (ImGui::BeginMenu("Sub-menu"))
2956             {
2957                 ImGui::MenuItem("Click me");
2958                 ImGui::EndMenu();
2959             }
2960 
2961             ImGui::Separator();
2962             ImGui::Text("Tooltip here");
2963             if (ImGui::IsItemHovered())
2964                 ImGui::SetTooltip("I am a tooltip over a popup");
2965 
2966             if (ImGui::Button("Stacked Popup"))
2967                 ImGui::OpenPopup("another popup");
2968             if (ImGui::BeginPopup("another popup"))
2969             {
2970                 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
2971                     ImGui::MenuItem(names[i], "", &toggles[i]);
2972                 if (ImGui::BeginMenu("Sub-menu"))
2973                 {
2974                     ImGui::MenuItem("Click me");
2975                     if (ImGui::Button("Stacked Popup"))
2976                         ImGui::OpenPopup("another popup");
2977                     if (ImGui::BeginPopup("another popup"))
2978                     {
2979                         ImGui::Text("I am the last one here.");
2980                         ImGui::EndPopup();
2981                     }
2982                     ImGui::EndMenu();
2983                 }
2984                 ImGui::EndPopup();
2985             }
2986             ImGui::EndPopup();
2987         }
2988 
2989         // Call the more complete ShowExampleMenuFile which we use in various places of this demo
2990         if (ImGui::Button("File Menu.."))
2991             ImGui::OpenPopup("my_file_popup");
2992         if (ImGui::BeginPopup("my_file_popup"))
2993         {
2994             ShowExampleMenuFile();
2995             ImGui::EndPopup();
2996         }
2997 
2998         ImGui::TreePop();
2999     }
3000 
3001     if (ImGui::TreeNode("Context menus"))
3002     {
3003         // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
3004         //    if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
3005         //       OpenPopup(id);
3006         //    return BeginPopup(id);
3007         // For more advanced uses you may want to replicate and customize this code.
3008         // See details in BeginPopupContextItem().
3009         static float value = 0.5f;
3010         ImGui::Text("Value = %.3f (<-- right-click here)", value);
3011         if (ImGui::BeginPopupContextItem("item context menu"))
3012         {
3013             if (ImGui::Selectable("Set to zero")) value = 0.0f;
3014             if (ImGui::Selectable("Set to PI")) value = 3.1415f;
3015             ImGui::SetNextItemWidth(-1);
3016             ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
3017             ImGui::EndPopup();
3018         }
3019 
3020         // We can also use OpenPopupContextItem() which is the same as BeginPopupContextItem() but without the
3021         // Begin() call. So here we will make it that clicking on the text field with the right mouse button (1)
3022         // will toggle the visibility of the popup above.
3023         ImGui::Text("(You can also right-click me to open the same popup as above.)");
3024         ImGui::OpenPopupContextItem("item context menu", 1);
3025 
3026         // When used after an item that has an ID (e.g.Button), we can skip providing an ID to BeginPopupContextItem().
3027         // BeginPopupContextItem() will use the last item ID as the popup ID.
3028         // In addition here, we want to include your editable label inside the button label.
3029         // We use the ### operator to override the ID (read FAQ about ID for details)
3030         static char name[32] = "Label1";
3031         char buf[64];
3032         sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
3033         ImGui::Button(buf);
3034         if (ImGui::BeginPopupContextItem())
3035         {
3036             ImGui::Text("Edit name:");
3037             ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
3038             if (ImGui::Button("Close"))
3039                 ImGui::CloseCurrentPopup();
3040             ImGui::EndPopup();
3041         }
3042         ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
3043 
3044         ImGui::TreePop();
3045     }
3046 
3047     if (ImGui::TreeNode("Modals"))
3048     {
3049         ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
3050 
3051         if (ImGui::Button("Delete.."))
3052             ImGui::OpenPopup("Delete?");
3053 
3054         // Always center this window when appearing
3055         ImVec2 center = ImGui::GetMainViewport()->GetCenter();
3056         //ImVec2 parent_pos = ImGui::GetWindowPos();
3057         //ImVec2 parent_size = ImGui::GetWindowSize();
3058         //ImVec2 center(parent_pos.x + parent_size.x * 0.5f, parent_pos.y + parent_size.y * 0.5f);
3059         ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
3060 
3061         if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
3062         {
3063             ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
3064             ImGui::Separator();
3065 
3066             //static int unused_i = 0;
3067             //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
3068 
3069             static bool dont_ask_me_next_time = false;
3070             ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3071             ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
3072             ImGui::PopStyleVar();
3073 
3074             if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3075             ImGui::SetItemDefaultFocus();
3076             ImGui::SameLine();
3077             if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3078             ImGui::EndPopup();
3079         }
3080 
3081         if (ImGui::Button("Stacked modals.."))
3082             ImGui::OpenPopup("Stacked 1");
3083         if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
3084         {
3085             if (ImGui::BeginMenuBar())
3086             {
3087                 if (ImGui::BeginMenu("File"))
3088                 {
3089                     if (ImGui::MenuItem("Some menu item")) {}
3090                     ImGui::EndMenu();
3091                 }
3092                 ImGui::EndMenuBar();
3093             }
3094             ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
3095 
3096             // Testing behavior of widgets stacking their own regular popups over the modal.
3097             static int item = 1;
3098             static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
3099             ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
3100             ImGui::ColorEdit4("color", color);
3101 
3102             if (ImGui::Button("Add another modal.."))
3103                 ImGui::OpenPopup("Stacked 2");
3104 
3105             // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
3106             // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
3107             // of the bool actually doesn't matter here.
3108             bool unused_open = true;
3109             if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
3110             {
3111                 ImGui::Text("Hello from Stacked The Second!");
3112                 if (ImGui::Button("Close"))
3113                     ImGui::CloseCurrentPopup();
3114                 ImGui::EndPopup();
3115             }
3116 
3117             if (ImGui::Button("Close"))
3118                 ImGui::CloseCurrentPopup();
3119             ImGui::EndPopup();
3120         }
3121 
3122         ImGui::TreePop();
3123     }
3124 
3125     if (ImGui::TreeNode("Menus inside a regular window"))
3126     {
3127         ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
3128         ImGui::Separator();
3129 
3130         // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the
3131         // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block
3132         // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would
3133         // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it,
3134         // which is the desired behavior for regular menus.
3135         ImGui::PushID("foo");
3136         ImGui::MenuItem("Menu item", "CTRL+M");
3137         if (ImGui::BeginMenu("Menu inside a regular window"))
3138         {
3139             ShowExampleMenuFile();
3140             ImGui::EndMenu();
3141         }
3142         ImGui::PopID();
3143         ImGui::Separator();
3144         ImGui::TreePop();
3145     }
3146 }
3147 
ShowDemoWindowColumns()3148 static void ShowDemoWindowColumns()
3149 {
3150     if (!ImGui::CollapsingHeader("Columns"))
3151         return;
3152 
3153     ImGui::PushID("Columns");
3154 
3155     static bool disable_indent = false;
3156     ImGui::Checkbox("Disable tree indentation", &disable_indent);
3157     ImGui::SameLine();
3158     HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width.");
3159     if (disable_indent)
3160         ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
3161 
3162     // Basic columns
3163     if (ImGui::TreeNode("Basic"))
3164     {
3165         ImGui::Text("Without border:");
3166         ImGui::Columns(3, "mycolumns3", false);  // 3-ways, no border
3167         ImGui::Separator();
3168         for (int n = 0; n < 14; n++)
3169         {
3170             char label[32];
3171             sprintf(label, "Item %d", n);
3172             if (ImGui::Selectable(label)) {}
3173             //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
3174             ImGui::NextColumn();
3175         }
3176         ImGui::Columns(1);
3177         ImGui::Separator();
3178 
3179         ImGui::Text("With border:");
3180         ImGui::Columns(4, "mycolumns"); // 4-ways, with border
3181         ImGui::Separator();
3182         ImGui::Text("ID"); ImGui::NextColumn();
3183         ImGui::Text("Name"); ImGui::NextColumn();
3184         ImGui::Text("Path"); ImGui::NextColumn();
3185         ImGui::Text("Hovered"); ImGui::NextColumn();
3186         ImGui::Separator();
3187         const char* names[3] = { "One", "Two", "Three" };
3188         const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
3189         static int selected = -1;
3190         for (int i = 0; i < 3; i++)
3191         {
3192             char label[32];
3193             sprintf(label, "%04d", i);
3194             if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
3195                 selected = i;
3196             bool hovered = ImGui::IsItemHovered();
3197             ImGui::NextColumn();
3198             ImGui::Text(names[i]); ImGui::NextColumn();
3199             ImGui::Text(paths[i]); ImGui::NextColumn();
3200             ImGui::Text("%d", hovered); ImGui::NextColumn();
3201         }
3202         ImGui::Columns(1);
3203         ImGui::Separator();
3204         ImGui::TreePop();
3205     }
3206 
3207     if (ImGui::TreeNode("Borders"))
3208     {
3209         // NB: Future columns API should allow automatic horizontal borders.
3210         static bool h_borders = true;
3211         static bool v_borders = true;
3212         static int columns_count = 4;
3213         const int lines_count = 3;
3214         ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
3215         ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
3216         if (columns_count < 2)
3217             columns_count = 2;
3218         ImGui::SameLine();
3219         ImGui::Checkbox("horizontal", &h_borders);
3220         ImGui::SameLine();
3221         ImGui::Checkbox("vertical", &v_borders);
3222         ImGui::Columns(columns_count, NULL, v_borders);
3223         for (int i = 0; i < columns_count * lines_count; i++)
3224         {
3225             if (h_borders && ImGui::GetColumnIndex() == 0)
3226                 ImGui::Separator();
3227             ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
3228             ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
3229             ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
3230             ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
3231             ImGui::Text("Long text that is likely to clip");
3232             ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
3233             ImGui::NextColumn();
3234         }
3235         ImGui::Columns(1);
3236         if (h_borders)
3237             ImGui::Separator();
3238         ImGui::TreePop();
3239     }
3240 
3241     // Create multiple items in a same cell before switching to next column
3242     if (ImGui::TreeNode("Mixed items"))
3243     {
3244         ImGui::Columns(3, "mixed");
3245         ImGui::Separator();
3246 
3247         ImGui::Text("Hello");
3248         ImGui::Button("Banana");
3249         ImGui::NextColumn();
3250 
3251         ImGui::Text("ImGui");
3252         ImGui::Button("Apple");
3253         static float foo = 1.0f;
3254         ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
3255         ImGui::Text("An extra line here.");
3256         ImGui::NextColumn();
3257 
3258         ImGui::Text("Sailor");
3259         ImGui::Button("Corniflower");
3260         static float bar = 1.0f;
3261         ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
3262         ImGui::NextColumn();
3263 
3264         if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
3265         if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
3266         if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
3267         ImGui::Columns(1);
3268         ImGui::Separator();
3269         ImGui::TreePop();
3270     }
3271 
3272     // Word wrapping
3273     if (ImGui::TreeNode("Word-wrapping"))
3274     {
3275         ImGui::Columns(2, "word-wrapping");
3276         ImGui::Separator();
3277         ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
3278         ImGui::TextWrapped("Hello Left");
3279         ImGui::NextColumn();
3280         ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
3281         ImGui::TextWrapped("Hello Right");
3282         ImGui::Columns(1);
3283         ImGui::Separator();
3284         ImGui::TreePop();
3285     }
3286 
3287     // Scrolling columns
3288     /*
3289     if (ImGui::TreeNode("Vertical Scrolling"))
3290     {
3291         ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
3292         ImGui::Columns(3);
3293         ImGui::Text("ID"); ImGui::NextColumn();
3294         ImGui::Text("Name"); ImGui::NextColumn();
3295         ImGui::Text("Path"); ImGui::NextColumn();
3296         ImGui::Columns(1);
3297         ImGui::Separator();
3298         ImGui::EndChild();
3299         ImGui::BeginChild("##scrollingregion", ImVec2(0, 60));
3300         ImGui::Columns(3);
3301         for (int i = 0; i < 10; i++)
3302         {
3303             ImGui::Text("%04d", i); ImGui::NextColumn();
3304             ImGui::Text("Foobar"); ImGui::NextColumn();
3305             ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn();
3306         }
3307         ImGui::Columns(1);
3308         ImGui::EndChild();
3309         ImGui::TreePop();
3310     }
3311     */
3312 
3313     if (ImGui::TreeNode("Horizontal Scrolling"))
3314     {
3315         ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
3316         ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
3317         ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar);
3318         ImGui::Columns(10);
3319         int ITEMS_COUNT = 2000;
3320         ImGuiListClipper clipper(ITEMS_COUNT);  // Also demonstrate using the clipper for large list
3321         while (clipper.Step())
3322         {
3323             for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
3324                 for (int j = 0; j < 10; j++)
3325                 {
3326                     ImGui::Text("Line %d Column %d...", i, j);
3327                     ImGui::NextColumn();
3328                 }
3329         }
3330         ImGui::Columns(1);
3331         ImGui::EndChild();
3332         ImGui::TreePop();
3333     }
3334 
3335     if (ImGui::TreeNode("Tree"))
3336     {
3337         ImGui::Columns(2, "tree", true);
3338         for (int x = 0; x < 3; x++)
3339         {
3340             bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
3341             ImGui::NextColumn();
3342             ImGui::Text("Node contents");
3343             ImGui::NextColumn();
3344             if (open1)
3345             {
3346                 for (int y = 0; y < 3; y++)
3347                 {
3348                     bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
3349                     ImGui::NextColumn();
3350                     ImGui::Text("Node contents");
3351                     if (open2)
3352                     {
3353                         ImGui::Text("Even more contents");
3354                         if (ImGui::TreeNode("Tree in column"))
3355                         {
3356                             ImGui::Text("The quick brown fox jumps over the lazy dog");
3357                             ImGui::TreePop();
3358                         }
3359                     }
3360                     ImGui::NextColumn();
3361                     if (open2)
3362                         ImGui::TreePop();
3363                 }
3364                 ImGui::TreePop();
3365             }
3366         }
3367         ImGui::Columns(1);
3368         ImGui::TreePop();
3369     }
3370 
3371     if (disable_indent)
3372         ImGui::PopStyleVar();
3373     ImGui::PopID();
3374 }
3375 
ShowDemoWindowMisc()3376 static void ShowDemoWindowMisc()
3377 {
3378     if (ImGui::CollapsingHeader("Filtering"))
3379     {
3380         // Helper class to easy setup a text filter.
3381         // You may want to implement a more feature-full filtering scheme in your own application.
3382         static ImGuiTextFilter filter;
3383         ImGui::Text("Filter usage:\n"
3384                     "  \"\"         display all lines\n"
3385                     "  \"xxx\"      display lines containing \"xxx\"\n"
3386                     "  \"xxx,yyy\"  display lines containing \"xxx\" or \"yyy\"\n"
3387                     "  \"-xxx\"     hide lines containing \"xxx\"");
3388         filter.Draw();
3389         const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
3390         for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
3391             if (filter.PassFilter(lines[i]))
3392                 ImGui::BulletText("%s", lines[i]);
3393     }
3394 
3395     if (ImGui::CollapsingHeader("Inputs, Navigation & Focus"))
3396     {
3397         ImGuiIO& io = ImGui::GetIO();
3398 
3399         // Display ImGuiIO output flags
3400         ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
3401         ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
3402         ImGui::Text("WantTextInput: %d", io.WantTextInput);
3403         ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos);
3404         ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible);
3405 
3406         // Display Keyboard/Mouse state
3407         if (ImGui::TreeNode("Keyboard, Mouse & Navigation State"))
3408         {
3409             if (ImGui::IsMousePosValid())
3410                 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
3411             else
3412                 ImGui::Text("Mouse pos: <INVALID>");
3413             ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
3414             ImGui::Text("Mouse down:");     for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f)   { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
3415             ImGui::Text("Mouse clicked:");  for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i))          { ImGui::SameLine(); ImGui::Text("b%d", i); }
3416             ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i))    { ImGui::SameLine(); ImGui::Text("b%d", i); }
3417             ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i))         { ImGui::SameLine(); ImGui::Text("b%d", i); }
3418             ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
3419 
3420             ImGui::Text("Keys down:");      for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f)     { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); }
3421             ImGui::Text("Keys pressed:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i))             { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); }
3422             ImGui::Text("Keys release:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i))            { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); }
3423             ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
3424             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.
3425 
3426             ImGui::Text("NavInputs down:");     for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f)              { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); }
3427             ImGui::Text("NavInputs pressed:");  for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); }
3428             ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); }
3429 
3430             ImGui::Button("Hovering me sets the\nkeyboard capture flag");
3431             if (ImGui::IsItemHovered())
3432                 ImGui::CaptureKeyboardFromApp(true);
3433             ImGui::SameLine();
3434             ImGui::Button("Holding me clears the\nthe keyboard capture flag");
3435             if (ImGui::IsItemActive())
3436                 ImGui::CaptureKeyboardFromApp(false);
3437 
3438             ImGui::TreePop();
3439         }
3440 
3441         if (ImGui::TreeNode("Tabbing"))
3442         {
3443             ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
3444             static char buf[32] = "hello";
3445             ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
3446             ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
3447             ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
3448             ImGui::PushAllowKeyboardFocus(false);
3449             ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
3450             //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool) to disable tabbing through certain widgets.");
3451             ImGui::PopAllowKeyboardFocus();
3452             ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
3453             ImGui::TreePop();
3454         }
3455 
3456         if (ImGui::TreeNode("Focus from code"))
3457         {
3458             bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
3459             bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
3460             bool focus_3 = ImGui::Button("Focus on 3");
3461             int has_focus = 0;
3462             static char buf[128] = "click on a button to set focus";
3463 
3464             if (focus_1) ImGui::SetKeyboardFocusHere();
3465             ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
3466             if (ImGui::IsItemActive()) has_focus = 1;
3467 
3468             if (focus_2) ImGui::SetKeyboardFocusHere();
3469             ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
3470             if (ImGui::IsItemActive()) has_focus = 2;
3471 
3472             ImGui::PushAllowKeyboardFocus(false);
3473             if (focus_3) ImGui::SetKeyboardFocusHere();
3474             ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
3475             if (ImGui::IsItemActive()) has_focus = 3;
3476             ImGui::PopAllowKeyboardFocus();
3477 
3478             if (has_focus)
3479                 ImGui::Text("Item with focus: %d", has_focus);
3480             else
3481                 ImGui::Text("Item with focus: <none>");
3482 
3483             // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
3484             static float f3[3] = { 0.0f, 0.0f, 0.0f };
3485             int focus_ahead = -1;
3486             if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
3487             if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
3488             if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
3489             if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
3490             ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
3491 
3492             ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
3493             ImGui::TreePop();
3494         }
3495 
3496         if (ImGui::TreeNode("Dragging"))
3497         {
3498             ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
3499             for (int button = 0; button < 3; button++)
3500             {
3501                 ImGui::Text("IsMouseDragging(%d):", button);
3502                 ImGui::Text("  w/ default threshold: %d,", ImGui::IsMouseDragging(button));
3503                 ImGui::Text("  w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
3504                 ImGui::Text("  w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
3505             }
3506 
3507             ImGui::Button("Drag Me");
3508             if (ImGui::IsItemActive())
3509                 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
3510 
3511             // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
3512             // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
3513             // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
3514             ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
3515             ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
3516             ImVec2 mouse_delta = io.MouseDelta;
3517             ImGui::Text("GetMouseDragDelta(0):");
3518             ImGui::Text("  w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
3519             ImGui::Text("  w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
3520             ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
3521             ImGui::TreePop();
3522         }
3523 
3524         if (ImGui::TreeNode("Mouse cursors"))
3525         {
3526             const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
3527             IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
3528 
3529             ImGuiMouseCursor current = ImGui::GetMouseCursor();
3530             ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
3531             ImGui::Text("Hover to see mouse cursors:");
3532             ImGui::SameLine(); HelpMarker(
3533                 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
3534                 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
3535                 "otherwise your backend needs to handle it.");
3536             for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
3537             {
3538                 char label[32];
3539                 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
3540                 ImGui::Bullet(); ImGui::Selectable(label, false);
3541                 if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
3542                     ImGui::SetMouseCursor(i);
3543             }
3544             ImGui::TreePop();
3545         }
3546     }
3547 }
3548 
3549 //-----------------------------------------------------------------------------
3550 // [SECTION] About Window / ShowAboutWindow()
3551 // Access from Dear ImGui Demo -> Tools -> About
3552 //-----------------------------------------------------------------------------
3553 
ShowAboutWindow(bool * p_open)3554 void ImGui::ShowAboutWindow(bool* p_open)
3555 {
3556     if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
3557     {
3558         ImGui::End();
3559         return;
3560     }
3561     ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
3562     ImGui::Separator();
3563     ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
3564     ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
3565 
3566     static bool show_config_info = false;
3567     ImGui::Checkbox("Config/Build Information", &show_config_info);
3568     if (show_config_info)
3569     {
3570         ImGuiIO& io = ImGui::GetIO();
3571         ImGuiStyle& style = ImGui::GetStyle();
3572 
3573         bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
3574         ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
3575         ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove);
3576         if (copy_to_clipboard)
3577         {
3578             ImGui::LogToClipboard();
3579             ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
3580         }
3581 
3582         ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
3583         ImGui::Separator();
3584         ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
3585         ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
3586 #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
3587         ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
3588 #endif
3589 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
3590         ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
3591 #endif
3592 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
3593         ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
3594 #endif
3595 #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
3596         ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
3597 #endif
3598 #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
3599         ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
3600 #endif
3601 #ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
3602         ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
3603 #endif
3604 #ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
3605         ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
3606 #endif
3607 #ifdef IMGUI_DISABLE_FILE_FUNCTIONS
3608         ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
3609 #endif
3610 #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
3611         ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
3612 #endif
3613 #ifdef IMGUI_USE_BGRA_PACKED_COLOR
3614         ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
3615 #endif
3616 #ifdef _WIN32
3617         ImGui::Text("define: _WIN32");
3618 #endif
3619 #ifdef _WIN64
3620         ImGui::Text("define: _WIN64");
3621 #endif
3622 #ifdef __linux__
3623         ImGui::Text("define: __linux__");
3624 #endif
3625 #ifdef __APPLE__
3626         ImGui::Text("define: __APPLE__");
3627 #endif
3628 #ifdef _MSC_VER
3629         ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
3630 #endif
3631 #ifdef __MINGW32__
3632         ImGui::Text("define: __MINGW32__");
3633 #endif
3634 #ifdef __MINGW64__
3635         ImGui::Text("define: __MINGW64__");
3636 #endif
3637 #ifdef __GNUC__
3638         ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
3639 #endif
3640 #ifdef __clang_version__
3641         ImGui::Text("define: __clang_version__=%s", __clang_version__);
3642 #endif
3643 #ifdef IMGUI_HAS_VIEWPORT
3644         ImGui::Text("define: IMGUI_HAS_VIEWPORT");
3645 #endif
3646 #ifdef IMGUI_HAS_DOCK
3647         ImGui::Text("define: IMGUI_HAS_DOCK");
3648 #endif
3649         ImGui::Separator();
3650         ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
3651         ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
3652         ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
3653         if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)        ImGui::Text(" NavEnableKeyboard");
3654         if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)         ImGui::Text(" NavEnableGamepad");
3655         if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)     ImGui::Text(" NavEnableSetMousePos");
3656         if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)     ImGui::Text(" NavNoCaptureKeyboard");
3657         if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)                  ImGui::Text(" NoMouse");
3658         if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)      ImGui::Text(" NoMouseCursorChange");
3659         if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)            ImGui::Text(" DockingEnable");
3660         if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)          ImGui::Text(" ViewportsEnable");
3661         if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports)  ImGui::Text(" DpiEnableScaleViewports");
3662         if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts)      ImGui::Text(" DpiEnableScaleFonts");
3663         if (io.MouseDrawCursor)                                         ImGui::Text("io.MouseDrawCursor");
3664         if (io.ConfigViewportsNoAutoMerge)                              ImGui::Text("io.ConfigViewportsNoAutoMerge");
3665         if (io.ConfigViewportsNoTaskBarIcon)                            ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
3666         if (io.ConfigViewportsNoDecoration)                             ImGui::Text("io.ConfigViewportsNoDecoration");
3667         if (io.ConfigViewportsNoDefaultParent)                          ImGui::Text("io.ConfigViewportsNoDefaultParent");
3668         if (io.ConfigDockingNoSplit)                                    ImGui::Text("io.ConfigDockingNoSplit");
3669         if (io.ConfigDockingWithShift)                                  ImGui::Text("io.ConfigDockingWithShift");
3670         if (io.ConfigDockingAlwaysTabBar)                               ImGui::Text("io.ConfigDockingAlwaysTabBar");
3671         if (io.ConfigDockingTransparentPayload)                         ImGui::Text("io.ConfigDockingTransparentPayload");
3672         if (io.ConfigMacOSXBehaviors)                                   ImGui::Text("io.ConfigMacOSXBehaviors");
3673         if (io.ConfigInputTextCursorBlink)                              ImGui::Text("io.ConfigInputTextCursorBlink");
3674         if (io.ConfigWindowsResizeFromEdges)                            ImGui::Text("io.ConfigWindowsResizeFromEdges");
3675         if (io.ConfigWindowsMoveFromTitleBarOnly)                       ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
3676         if (io.ConfigWindowsMemoryCompactTimer >= 0.0f)                 ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer);
3677         ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
3678         if (io.BackendFlags & ImGuiBackendFlags_HasGamepad)             ImGui::Text(" HasGamepad");
3679         if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)        ImGui::Text(" HasMouseCursors");
3680         if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)         ImGui::Text(" HasSetMousePos");
3681         if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)   ImGui::Text(" PlatformHasViewports");
3682         if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
3683         if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)   ImGui::Text(" RendererHasVtxOffset");
3684         if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports)   ImGui::Text(" RendererHasViewports");
3685         ImGui::Separator();
3686         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);
3687         ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
3688         ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
3689         ImGui::Separator();
3690         ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
3691         ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
3692         ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
3693         ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
3694         ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
3695         ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
3696         ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
3697 
3698         if (copy_to_clipboard)
3699         {
3700             ImGui::LogText("\n```\n");
3701             ImGui::LogFinish();
3702         }
3703         ImGui::EndChildFrame();
3704     }
3705     ImGui::End();
3706 }
3707 
3708 //-----------------------------------------------------------------------------
3709 // [SECTION] Style Editor / ShowStyleEditor()
3710 //-----------------------------------------------------------------------------
3711 // - ShowStyleSelector()
3712 // - ShowFontSelector()
3713 // - ShowStyleEditor()
3714 //-----------------------------------------------------------------------------
3715 
3716 // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
3717 // Here we use the simplified Combo() api that packs items into a single literal string.
3718 // Useful for quick combo boxes where the choices are known locally.
ShowStyleSelector(const char * label)3719 bool ImGui::ShowStyleSelector(const char* label)
3720 {
3721     static int style_idx = -1;
3722     if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))
3723     {
3724         switch (style_idx)
3725         {
3726         case 0: ImGui::StyleColorsClassic(); break;
3727         case 1: ImGui::StyleColorsDark(); break;
3728         case 2: ImGui::StyleColorsLight(); break;
3729         }
3730         return true;
3731     }
3732     return false;
3733 }
3734 
3735 // Demo helper function to select among loaded fonts.
3736 // Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one.
ShowFontSelector(const char * label)3737 void ImGui::ShowFontSelector(const char* label)
3738 {
3739     ImGuiIO& io = ImGui::GetIO();
3740     ImFont* font_current = ImGui::GetFont();
3741     if (ImGui::BeginCombo(label, font_current->GetDebugName()))
3742     {
3743         for (int n = 0; n < io.Fonts->Fonts.Size; n++)
3744         {
3745             ImFont* font = io.Fonts->Fonts[n];
3746             ImGui::PushID((void*)font);
3747             if (ImGui::Selectable(font->GetDebugName(), font == font_current))
3748                 io.FontDefault = font;
3749             ImGui::PopID();
3750         }
3751         ImGui::EndCombo();
3752     }
3753     ImGui::SameLine();
3754     HelpMarker(
3755         "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
3756         "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
3757         "- Read FAQ and docs/FONTS.md for more details.\n"
3758         "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
3759 }
3760 
3761 // [Internal] Display details for a single font, called by ShowStyleEditor().
NodeFont(ImFont * font)3762 static void NodeFont(ImFont* font)
3763 {
3764     ImGuiIO& io = ImGui::GetIO();
3765     ImGuiStyle& style = ImGui::GetStyle();
3766     bool font_details_opened = ImGui::TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)",
3767         font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
3768     ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; }
3769     if (!font_details_opened)
3770         return;
3771 
3772     ImGui::PushFont(font);
3773     ImGui::Text("The quick brown fox jumps over the lazy dog");
3774     ImGui::PopFont();
3775     ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f");   // Scale only this font
3776     ImGui::SameLine(); HelpMarker(
3777         "Note than the default embedded font is NOT meant to be scaled.\n\n"
3778         "Font are currently rendered into bitmaps at a given size at the time of building the atlas. "
3779         "You may oversample them to get some flexibility with scaling. "
3780         "You can also render at multiple sizes and select which one to use at runtime.\n\n"
3781         "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
3782     ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f");
3783     ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
3784     ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar);
3785     ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar);
3786     const int surface_sqrt = (int)sqrtf((float)font->MetricsTotalSurface);
3787     ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);
3788     for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
3789         if (font->ConfigData)
3790             if (const ImFontConfig* cfg = &font->ConfigData[config_i])
3791                 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d",
3792                     config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
3793     if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
3794     {
3795         // Display all glyphs of the fonts in separate pages of 256 characters
3796         const ImU32 glyph_col = ImGui::GetColorU32(ImGuiCol_Text);
3797         for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
3798         {
3799             // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
3800             // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
3801             // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
3802             if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
3803             {
3804                 base += 4096 - 256;
3805                 continue;
3806             }
3807 
3808             int count = 0;
3809             for (unsigned int n = 0; n < 256; n++)
3810                 if (font->FindGlyphNoFallback((ImWchar)(base + n)))
3811                     count++;
3812             if (count <= 0)
3813                 continue;
3814             if (!ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
3815                 continue;
3816             float cell_size = font->FontSize * 1;
3817             float cell_spacing = style.ItemSpacing.y;
3818             ImVec2 base_pos = ImGui::GetCursorScreenPos();
3819             ImDrawList* draw_list = ImGui::GetWindowDrawList();
3820             for (unsigned int n = 0; n < 256; n++)
3821             {
3822                 // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
3823                 // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
3824                 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
3825                 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
3826                 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
3827                 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
3828                 if (glyph)
3829                     font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
3830                 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
3831                 {
3832                     ImGui::BeginTooltip();
3833                     ImGui::Text("Codepoint: U+%04X", base + n);
3834                     ImGui::Separator();
3835                     ImGui::Text("Visible: %d", glyph->Visible);
3836                     ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
3837                     ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
3838                     ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
3839                     ImGui::EndTooltip();
3840                 }
3841             }
3842             ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
3843             ImGui::TreePop();
3844         }
3845         ImGui::TreePop();
3846     }
3847     ImGui::TreePop();
3848 }
3849 
ShowStyleEditor(ImGuiStyle * ref)3850 void ImGui::ShowStyleEditor(ImGuiStyle* ref)
3851 {
3852     // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
3853     // (without a reference style pointer, we will use one compared locally as a reference)
3854     ImGuiStyle& style = ImGui::GetStyle();
3855     static ImGuiStyle ref_saved_style;
3856 
3857     // Default to using internal storage as reference
3858     static bool init = true;
3859     if (init && ref == NULL)
3860         ref_saved_style = style;
3861     init = false;
3862     if (ref == NULL)
3863         ref = &ref_saved_style;
3864 
3865     ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
3866 
3867     if (ImGui::ShowStyleSelector("Colors##Selector"))
3868         ref_saved_style = style;
3869     ImGui::ShowFontSelector("Fonts##Selector");
3870 
3871     // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
3872     if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
3873         style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
3874     { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
3875     ImGui::SameLine();
3876     { bool border = (style.FrameBorderSize > 0.0f);  if (ImGui::Checkbox("FrameBorder",  &border)) { style.FrameBorderSize  = border ? 1.0f : 0.0f; } }
3877     ImGui::SameLine();
3878     { bool border = (style.PopupBorderSize > 0.0f);  if (ImGui::Checkbox("PopupBorder",  &border)) { style.PopupBorderSize  = border ? 1.0f : 0.0f; } }
3879 
3880     // Save/Revert button
3881     if (ImGui::Button("Save Ref"))
3882         *ref = ref_saved_style = style;
3883     ImGui::SameLine();
3884     if (ImGui::Button("Revert Ref"))
3885         style = *ref;
3886     ImGui::SameLine();
3887     HelpMarker(
3888         "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
3889         "Use \"Export\" below to save them somewhere.");
3890 
3891     ImGui::Separator();
3892 
3893     if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
3894     {
3895         if (ImGui::BeginTabItem("Sizes"))
3896         {
3897             ImGui::Text("Main");
3898             ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
3899             ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
3900             ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
3901             ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
3902             ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
3903             ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
3904             ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
3905             ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
3906             ImGui::Text("Borders");
3907             ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
3908             ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
3909             ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
3910             ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
3911             ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
3912             ImGui::Text("Rounding");
3913             ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
3914             ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
3915             ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
3916             ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
3917             ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
3918             ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
3919             ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
3920             ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
3921             ImGui::Text("Alignment");
3922             ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
3923             int window_menu_button_position = style.WindowMenuButtonPosition + 1;
3924             if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
3925                 style.WindowMenuButtonPosition = window_menu_button_position - 1;
3926             ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
3927             ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
3928             ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
3929             ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
3930             ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
3931             ImGui::Text("Safe Area Padding");
3932             ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
3933             ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
3934             ImGui::EndTabItem();
3935         }
3936 
3937         if (ImGui::BeginTabItem("Colors"))
3938         {
3939             static int output_dest = 0;
3940             static bool output_only_modified = true;
3941             if (ImGui::Button("Export"))
3942             {
3943                 if (output_dest == 0)
3944                     ImGui::LogToClipboard();
3945                 else
3946                     ImGui::LogToTTY();
3947                 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
3948                 for (int i = 0; i < ImGuiCol_COUNT; i++)
3949                 {
3950                     const ImVec4& col = style.Colors[i];
3951                     const char* name = ImGui::GetStyleColorName(i);
3952                     if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
3953                         ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
3954                             name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
3955                 }
3956                 ImGui::LogFinish();
3957             }
3958             ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
3959             ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
3960 
3961             static ImGuiTextFilter filter;
3962             filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
3963 
3964             static ImGuiColorEditFlags alpha_flags = 0;
3965             if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None))             { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
3966             if (ImGui::RadioButton("Alpha",  alpha_flags == ImGuiColorEditFlags_AlphaPreview))     { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
3967             if (ImGui::RadioButton("Both",   alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
3968             HelpMarker(
3969                 "In the color list:\n"
3970                 "Left-click on colored square to open color picker,\n"
3971                 "Right-click to open edit options menu.");
3972 
3973             ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
3974             ImGui::PushItemWidth(-160);
3975             for (int i = 0; i < ImGuiCol_COUNT; i++)
3976             {
3977                 const char* name = ImGui::GetStyleColorName(i);
3978                 if (!filter.PassFilter(name))
3979                     continue;
3980                 ImGui::PushID(i);
3981                 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
3982                 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
3983                 {
3984                     // Tips: in a real user application, you may want to merge and use an icon font into the main font,
3985                     // so instead of "Save"/"Revert" you'd use icons!
3986                     // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
3987                     ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
3988                     ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
3989                 }
3990                 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
3991                 ImGui::TextUnformatted(name);
3992                 ImGui::PopID();
3993             }
3994             ImGui::PopItemWidth();
3995             ImGui::EndChild();
3996 
3997             ImGui::EndTabItem();
3998         }
3999 
4000         if (ImGui::BeginTabItem("Fonts"))
4001         {
4002             ImGuiIO& io = ImGui::GetIO();
4003             ImFontAtlas* atlas = io.Fonts;
4004             HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
4005             ImGui::PushItemWidth(120);
4006             for (int i = 0; i < atlas->Fonts.Size; i++)
4007             {
4008                 ImFont* font = atlas->Fonts[i];
4009                 ImGui::PushID(font);
4010                 NodeFont(font);
4011                 ImGui::PopID();
4012             }
4013             if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
4014             {
4015                 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
4016                 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
4017                 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col);
4018                 ImGui::TreePop();
4019             }
4020 
4021             // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
4022             // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
4023             const float MIN_SCALE = 0.3f;
4024             const float MAX_SCALE = 2.0f;
4025             HelpMarker(
4026                 "Those are old settings provided for convenience.\n"
4027                 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
4028                 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
4029                 "Using those settings here will give you poor quality results.");
4030             static float window_scale = 1.0f;
4031             if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_ClampOnInput)) // Scale only this window
4032                 ImGui::SetWindowFontScale(window_scale);
4033             ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_ClampOnInput); // Scale everything
4034             ImGui::PopItemWidth();
4035 
4036             ImGui::EndTabItem();
4037         }
4038 
4039         if (ImGui::BeginTabItem("Rendering"))
4040         {
4041             ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
4042             ImGui::SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
4043             ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
4044             ImGui::SameLine(); HelpMarker("Faster lines using texture data. Require back-end to render with bilinear filtering (not point/nearest filtering).");
4045             ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
4046             ImGui::PushItemWidth(100);
4047             ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
4048             if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
4049 
4050             // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
4051             ImGui::DragFloat("Circle Segment Max Error", &style.CircleSegmentMaxError, 0.01f, 0.10f, 10.0f, "%.2f");
4052             if (ImGui::IsItemActive())
4053             {
4054                 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
4055                 ImGui::BeginTooltip();
4056                 ImVec2 p = ImGui::GetCursorScreenPos();
4057                 float RAD_MIN = 10.0f, RAD_MAX = 80.0f;
4058                 float off_x = 10.0f;
4059                 for (int n = 0; n < 7; n++)
4060                 {
4061                     const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (7.0f - 1.0f);
4062                     ImGui::GetWindowDrawList()->AddCircle(ImVec2(p.x + off_x + rad, p.y + RAD_MAX), rad, ImGui::GetColorU32(ImGuiCol_Text), 0);
4063                     off_x += 10.0f + rad * 2.0f;
4064                 }
4065                 ImGui::Dummy(ImVec2(off_x, RAD_MAX * 2.0f));
4066                 ImGui::EndTooltip();
4067             }
4068             ImGui::SameLine();
4069             HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
4070 
4071             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.
4072             ImGui::PopItemWidth();
4073 
4074             ImGui::EndTabItem();
4075         }
4076 
4077         ImGui::EndTabBar();
4078     }
4079 
4080     ImGui::PopItemWidth();
4081 }
4082 
4083 //-----------------------------------------------------------------------------
4084 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
4085 //-----------------------------------------------------------------------------
4086 // - ShowExampleAppMainMenuBar()
4087 // - ShowExampleMenuFile()
4088 //-----------------------------------------------------------------------------
4089 
4090 // Demonstrate creating a "main" fullscreen menu bar and populating it.
4091 // Note the difference between BeginMainMenuBar() and BeginMenuBar():
4092 // - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
4093 // - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
ShowExampleAppMainMenuBar()4094 static void ShowExampleAppMainMenuBar()
4095 {
4096     if (ImGui::BeginMainMenuBar())
4097     {
4098         if (ImGui::BeginMenu("File"))
4099         {
4100             ShowExampleMenuFile();
4101             ImGui::EndMenu();
4102         }
4103         if (ImGui::BeginMenu("Edit"))
4104         {
4105             if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
4106             if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
4107             ImGui::Separator();
4108             if (ImGui::MenuItem("Cut", "CTRL+X")) {}
4109             if (ImGui::MenuItem("Copy", "CTRL+C")) {}
4110             if (ImGui::MenuItem("Paste", "CTRL+V")) {}
4111             ImGui::EndMenu();
4112         }
4113         ImGui::EndMainMenuBar();
4114     }
4115 }
4116 
4117 // Note that shortcuts are currently provided for display only
4118 // (future version will add explicit flags to BeginMenu() to request processing shortcuts)
ShowExampleMenuFile()4119 static void ShowExampleMenuFile()
4120 {
4121     ImGui::MenuItem("(demo menu)", NULL, false, false);
4122     if (ImGui::MenuItem("New")) {}
4123     if (ImGui::MenuItem("Open", "Ctrl+O")) {}
4124     if (ImGui::BeginMenu("Open Recent"))
4125     {
4126         ImGui::MenuItem("fish_hat.c");
4127         ImGui::MenuItem("fish_hat.inl");
4128         ImGui::MenuItem("fish_hat.h");
4129         if (ImGui::BeginMenu("More.."))
4130         {
4131             ImGui::MenuItem("Hello");
4132             ImGui::MenuItem("Sailor");
4133             if (ImGui::BeginMenu("Recurse.."))
4134             {
4135                 ShowExampleMenuFile();
4136                 ImGui::EndMenu();
4137             }
4138             ImGui::EndMenu();
4139         }
4140         ImGui::EndMenu();
4141     }
4142     if (ImGui::MenuItem("Save", "Ctrl+S")) {}
4143     if (ImGui::MenuItem("Save As..")) {}
4144 
4145     ImGui::Separator();
4146     if (ImGui::BeginMenu("Options"))
4147     {
4148         static bool enabled = true;
4149         ImGui::MenuItem("Enabled", "", &enabled);
4150         ImGui::BeginChild("child", ImVec2(0, 60), true);
4151         for (int i = 0; i < 10; i++)
4152             ImGui::Text("Scrolling Text %d", i);
4153         ImGui::EndChild();
4154         static float f = 0.5f;
4155         static int n = 0;
4156         ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
4157         ImGui::InputFloat("Input", &f, 0.1f);
4158         ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
4159         ImGui::EndMenu();
4160     }
4161 
4162     if (ImGui::BeginMenu("Colors"))
4163     {
4164         float sz = ImGui::GetTextLineHeight();
4165         for (int i = 0; i < ImGuiCol_COUNT; i++)
4166         {
4167             const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
4168             ImVec2 p = ImGui::GetCursorScreenPos();
4169             ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
4170             ImGui::Dummy(ImVec2(sz, sz));
4171             ImGui::SameLine();
4172             ImGui::MenuItem(name);
4173         }
4174         ImGui::EndMenu();
4175     }
4176 
4177     // Here we demonstrate appending again to the "Options" menu (which we already created above)
4178     // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
4179     // In a real code-base using it would make senses to use this feature from very different code locations.
4180     if (ImGui::BeginMenu("Options")) // <-- Append!
4181     {
4182         static bool b = true;
4183         ImGui::Checkbox("SomeOption", &b);
4184         ImGui::EndMenu();
4185     }
4186 
4187     if (ImGui::BeginMenu("Disabled", false)) // Disabled
4188     {
4189         IM_ASSERT(0);
4190     }
4191     if (ImGui::MenuItem("Checked", NULL, true)) {}
4192     if (ImGui::MenuItem("Quit", "Alt+F4")) {}
4193 }
4194 
4195 //-----------------------------------------------------------------------------
4196 // [SECTION] Example App: Debug Console / ShowExampleAppConsole()
4197 //-----------------------------------------------------------------------------
4198 
4199 // Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
4200 // For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
4201 struct ExampleAppConsole
4202 {
4203     char                  InputBuf[256];
4204     ImVector<char*>       Items;
4205     ImVector<const char*> Commands;
4206     ImVector<char*>       History;
4207     int                   HistoryPos;    // -1: new line, 0..History.Size-1 browsing history.
4208     ImGuiTextFilter       Filter;
4209     bool                  AutoScroll;
4210     bool                  ScrollToBottom;
4211 
ExampleAppConsoleExampleAppConsole4212     ExampleAppConsole()
4213     {
4214         ClearLog();
4215         memset(InputBuf, 0, sizeof(InputBuf));
4216         HistoryPos = -1;
4217 
4218         // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
4219         Commands.push_back("HELP");
4220         Commands.push_back("HISTORY");
4221         Commands.push_back("CLEAR");
4222         Commands.push_back("CLASSIFY");
4223         AutoScroll = true;
4224         ScrollToBottom = false;
4225         AddLog("Welcome to Dear ImGui!");
4226     }
~ExampleAppConsoleExampleAppConsole4227     ~ExampleAppConsole()
4228     {
4229         ClearLog();
4230         for (int i = 0; i < History.Size; i++)
4231             free(History[i]);
4232     }
4233 
4234     // Portable helpers
StricmpExampleAppConsole4235     static int   Stricmp(const char* s1, const char* s2)         { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
StrnicmpExampleAppConsole4236     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; }
StrdupExampleAppConsole4237     static char* Strdup(const char* s)                           { size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
StrtrimExampleAppConsole4238     static void  Strtrim(char* s)                                { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
4239 
ClearLogExampleAppConsole4240     void    ClearLog()
4241     {
4242         for (int i = 0; i < Items.Size; i++)
4243             free(Items[i]);
4244         Items.clear();
4245     }
4246 
AddLogExampleAppConsole4247     void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
4248     {
4249         // FIXME-OPT
4250         char buf[1024];
4251         va_list args;
4252         va_start(args, fmt);
4253         vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
4254         buf[IM_ARRAYSIZE(buf)-1] = 0;
4255         va_end(args);
4256         Items.push_back(Strdup(buf));
4257     }
4258 
DrawExampleAppConsole4259     void    Draw(const char* title, bool* p_open)
4260     {
4261         ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
4262         if (!ImGui::Begin(title, p_open))
4263         {
4264             ImGui::End();
4265             return;
4266         }
4267 
4268         // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
4269         // So e.g. IsItemHovered() will return true when hovering the title bar.
4270         // Here we create a context menu only available from the title bar.
4271         if (ImGui::BeginPopupContextItem())
4272         {
4273             if (ImGui::MenuItem("Close Console"))
4274                 *p_open = false;
4275             ImGui::EndPopup();
4276         }
4277 
4278         ImGui::TextWrapped(
4279             "This example implements a console with basic coloring, completion and history. A more elaborate "
4280             "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
4281         ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion.");
4282 
4283         // TODO: display items starting from the bottom
4284 
4285         if (ImGui::SmallButton("Add Debug Text"))  { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine();
4286         if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine();
4287         if (ImGui::SmallButton("Clear"))           { ClearLog(); } ImGui::SameLine();
4288         bool copy_to_clipboard = ImGui::SmallButton("Copy");
4289         //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
4290 
4291         ImGui::Separator();
4292 
4293         // Options menu
4294         if (ImGui::BeginPopup("Options"))
4295         {
4296             ImGui::Checkbox("Auto-scroll", &AutoScroll);
4297             ImGui::EndPopup();
4298         }
4299 
4300         // Options, Filter
4301         if (ImGui::Button("Options"))
4302             ImGui::OpenPopup("Options");
4303         ImGui::SameLine();
4304         Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
4305         ImGui::Separator();
4306 
4307         // Reserve enough left-over height for 1 separator + 1 input text
4308         const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
4309         ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar);
4310         if (ImGui::BeginPopupContextWindow())
4311         {
4312             if (ImGui::Selectable("Clear")) ClearLog();
4313             ImGui::EndPopup();
4314         }
4315 
4316         // Display every line as a separate entry so we can change their color or add custom widgets.
4317         // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
4318         // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
4319         // to only process visible items. The clipper will automatically measure the height of your first item and then
4320         // "seek" to display only items in the visible area.
4321         // To use the clipper we can replace your standard loop:
4322         //      for (int i = 0; i < Items.Size; i++)
4323         //   With:
4324         //      ImGuiListClipper clipper(Items.Size);
4325         //      while (clipper.Step())
4326         //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
4327         // - That your items are evenly spaced (same height)
4328         // - That you have cheap random access to your elements (you can access them given their index,
4329         //   without processing all the ones before)
4330         // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
4331         // We would need random-access on the post-filtered list.
4332         // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
4333         // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
4334         // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
4335         // to improve this example code!
4336         // If your items are of variable height:
4337         // - Split them into same height items would be simpler and facilitate random-seeking into your list.
4338         // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
4339         ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
4340         if (copy_to_clipboard)
4341             ImGui::LogToClipboard();
4342         for (int i = 0; i < Items.Size; i++)
4343         {
4344             const char* item = Items[i];
4345             if (!Filter.PassFilter(item))
4346                 continue;
4347 
4348             // Normally you would store more information in your item than just a string.
4349             // (e.g. make Items[] an array of structure, store color/type etc.)
4350             ImVec4 color;
4351             bool has_color = false;
4352             if (strstr(item, "[error]"))          { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
4353             else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
4354             if (has_color)
4355                 ImGui::PushStyleColor(ImGuiCol_Text, color);
4356             ImGui::TextUnformatted(item);
4357             if (has_color)
4358                 ImGui::PopStyleColor();
4359         }
4360         if (copy_to_clipboard)
4361             ImGui::LogFinish();
4362 
4363         if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
4364             ImGui::SetScrollHereY(1.0f);
4365         ScrollToBottom = false;
4366 
4367         ImGui::PopStyleVar();
4368         ImGui::EndChild();
4369         ImGui::Separator();
4370 
4371         // Command-line
4372         bool reclaim_focus = false;
4373         ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
4374         if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
4375         {
4376             char* s = InputBuf;
4377             Strtrim(s);
4378             if (s[0])
4379                 ExecCommand(s);
4380             strcpy(s, "");
4381             reclaim_focus = true;
4382         }
4383 
4384         // Auto-focus on window apparition
4385         ImGui::SetItemDefaultFocus();
4386         if (reclaim_focus)
4387             ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
4388 
4389         ImGui::End();
4390     }
4391 
ExecCommandExampleAppConsole4392     void    ExecCommand(const char* command_line)
4393     {
4394         AddLog("# %s\n", command_line);
4395 
4396         // Insert into history. First find match and delete it so it can be pushed to the back.
4397         // This isn't trying to be smart or optimal.
4398         HistoryPos = -1;
4399         for (int i = History.Size - 1; i >= 0; i--)
4400             if (Stricmp(History[i], command_line) == 0)
4401             {
4402                 free(History[i]);
4403                 History.erase(History.begin() + i);
4404                 break;
4405             }
4406         History.push_back(Strdup(command_line));
4407 
4408         // Process command
4409         if (Stricmp(command_line, "CLEAR") == 0)
4410         {
4411             ClearLog();
4412         }
4413         else if (Stricmp(command_line, "HELP") == 0)
4414         {
4415             AddLog("Commands:");
4416             for (int i = 0; i < Commands.Size; i++)
4417                 AddLog("- %s", Commands[i]);
4418         }
4419         else if (Stricmp(command_line, "HISTORY") == 0)
4420         {
4421             int first = History.Size - 10;
4422             for (int i = first > 0 ? first : 0; i < History.Size; i++)
4423                 AddLog("%3d: %s\n", i, History[i]);
4424         }
4425         else
4426         {
4427             AddLog("Unknown command: '%s'\n", command_line);
4428         }
4429 
4430         // On command input, we scroll to bottom even if AutoScroll==false
4431         ScrollToBottom = true;
4432     }
4433 
4434     // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
TextEditCallbackStubExampleAppConsole4435     static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
4436     {
4437         ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
4438         return console->TextEditCallback(data);
4439     }
4440 
TextEditCallbackExampleAppConsole4441     int     TextEditCallback(ImGuiInputTextCallbackData* data)
4442     {
4443         //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
4444         switch (data->EventFlag)
4445         {
4446         case ImGuiInputTextFlags_CallbackCompletion:
4447             {
4448                 // Example of TEXT COMPLETION
4449 
4450                 // Locate beginning of current word
4451                 const char* word_end = data->Buf + data->CursorPos;
4452                 const char* word_start = word_end;
4453                 while (word_start > data->Buf)
4454                 {
4455                     const char c = word_start[-1];
4456                     if (c == ' ' || c == '\t' || c == ',' || c == ';')
4457                         break;
4458                     word_start--;
4459                 }
4460 
4461                 // Build a list of candidates
4462                 ImVector<const char*> candidates;
4463                 for (int i = 0; i < Commands.Size; i++)
4464                     if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
4465                         candidates.push_back(Commands[i]);
4466 
4467                 if (candidates.Size == 0)
4468                 {
4469                     // No match
4470                     AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
4471                 }
4472                 else if (candidates.Size == 1)
4473                 {
4474                     // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
4475                     data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
4476                     data->InsertChars(data->CursorPos, candidates[0]);
4477                     data->InsertChars(data->CursorPos, " ");
4478                 }
4479                 else
4480                 {
4481                     // Multiple matches. Complete as much as we can..
4482                     // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
4483                     int match_len = (int)(word_end - word_start);
4484                     for (;;)
4485                     {
4486                         int c = 0;
4487                         bool all_candidates_matches = true;
4488                         for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
4489                             if (i == 0)
4490                                 c = toupper(candidates[i][match_len]);
4491                             else if (c == 0 || c != toupper(candidates[i][match_len]))
4492                                 all_candidates_matches = false;
4493                         if (!all_candidates_matches)
4494                             break;
4495                         match_len++;
4496                     }
4497 
4498                     if (match_len > 0)
4499                     {
4500                         data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
4501                         data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
4502                     }
4503 
4504                     // List matches
4505                     AddLog("Possible matches:\n");
4506                     for (int i = 0; i < candidates.Size; i++)
4507                         AddLog("- %s\n", candidates[i]);
4508                 }
4509 
4510                 break;
4511             }
4512         case ImGuiInputTextFlags_CallbackHistory:
4513             {
4514                 // Example of HISTORY
4515                 const int prev_history_pos = HistoryPos;
4516                 if (data->EventKey == ImGuiKey_UpArrow)
4517                 {
4518                     if (HistoryPos == -1)
4519                         HistoryPos = History.Size - 1;
4520                     else if (HistoryPos > 0)
4521                         HistoryPos--;
4522                 }
4523                 else if (data->EventKey == ImGuiKey_DownArrow)
4524                 {
4525                     if (HistoryPos != -1)
4526                         if (++HistoryPos >= History.Size)
4527                             HistoryPos = -1;
4528                 }
4529 
4530                 // A better implementation would preserve the data on the current input line along with cursor position.
4531                 if (prev_history_pos != HistoryPos)
4532                 {
4533                     const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
4534                     data->DeleteChars(0, data->BufTextLen);
4535                     data->InsertChars(0, history_str);
4536                 }
4537             }
4538         }
4539         return 0;
4540     }
4541 };
4542 
ShowExampleAppConsole(bool * p_open)4543 static void ShowExampleAppConsole(bool* p_open)
4544 {
4545     static ExampleAppConsole console;
4546     console.Draw("Example: Console", p_open);
4547 }
4548 
4549 //-----------------------------------------------------------------------------
4550 // [SECTION] Example App: Debug Log / ShowExampleAppLog()
4551 //-----------------------------------------------------------------------------
4552 
4553 // Usage:
4554 //  static ExampleAppLog my_log;
4555 //  my_log.AddLog("Hello %d world\n", 123);
4556 //  my_log.Draw("title");
4557 struct ExampleAppLog
4558 {
4559     ImGuiTextBuffer     Buf;
4560     ImGuiTextFilter     Filter;
4561     ImVector<int>       LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
4562     bool                AutoScroll;  // Keep scrolling if already at the bottom.
4563 
ExampleAppLogExampleAppLog4564     ExampleAppLog()
4565     {
4566         AutoScroll = true;
4567         Clear();
4568     }
4569 
ClearExampleAppLog4570     void    Clear()
4571     {
4572         Buf.clear();
4573         LineOffsets.clear();
4574         LineOffsets.push_back(0);
4575     }
4576 
AddLogExampleAppLog4577     void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
4578     {
4579         int old_size = Buf.size();
4580         va_list args;
4581         va_start(args, fmt);
4582         Buf.appendfv(fmt, args);
4583         va_end(args);
4584         for (int new_size = Buf.size(); old_size < new_size; old_size++)
4585             if (Buf[old_size] == '\n')
4586                 LineOffsets.push_back(old_size + 1);
4587     }
4588 
DrawExampleAppLog4589     void    Draw(const char* title, bool* p_open = NULL)
4590     {
4591         if (!ImGui::Begin(title, p_open))
4592         {
4593             ImGui::End();
4594             return;
4595         }
4596 
4597         // Options menu
4598         if (ImGui::BeginPopup("Options"))
4599         {
4600             ImGui::Checkbox("Auto-scroll", &AutoScroll);
4601             ImGui::EndPopup();
4602         }
4603 
4604         // Main window
4605         if (ImGui::Button("Options"))
4606             ImGui::OpenPopup("Options");
4607         ImGui::SameLine();
4608         bool clear = ImGui::Button("Clear");
4609         ImGui::SameLine();
4610         bool copy = ImGui::Button("Copy");
4611         ImGui::SameLine();
4612         Filter.Draw("Filter", -100.0f);
4613 
4614         ImGui::Separator();
4615         ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
4616 
4617         if (clear)
4618             Clear();
4619         if (copy)
4620             ImGui::LogToClipboard();
4621 
4622         ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
4623         const char* buf = Buf.begin();
4624         const char* buf_end = Buf.end();
4625         if (Filter.IsActive())
4626         {
4627             // In this example we don't use the clipper when Filter is enabled.
4628             // This is because we don't have a random access on the result on our filter.
4629             // A real application processing logs with ten of thousands of entries may want to store the result of
4630             // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
4631             for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
4632             {
4633                 const char* line_start = buf + LineOffsets[line_no];
4634                 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
4635                 if (Filter.PassFilter(line_start, line_end))
4636                     ImGui::TextUnformatted(line_start, line_end);
4637             }
4638         }
4639         else
4640         {
4641             // The simplest and easy way to display the entire buffer:
4642             //   ImGui::TextUnformatted(buf_begin, buf_end);
4643             // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
4644             // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
4645             // within the visible area.
4646             // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
4647             // on your side is recommended. Using ImGuiListClipper requires
4648             // - A) random access into your data
4649             // - B) items all being the  same height,
4650             // both of which we can handle since we an array pointing to the beginning of each line of text.
4651             // When using the filter (in the block of code above) we don't have random access into the data to display
4652             // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
4653             // it possible (and would be recommended if you want to search through tens of thousands of entries).
4654             ImGuiListClipper clipper;
4655             clipper.Begin(LineOffsets.Size);
4656             while (clipper.Step())
4657             {
4658                 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
4659                 {
4660                     const char* line_start = buf + LineOffsets[line_no];
4661                     const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
4662                     ImGui::TextUnformatted(line_start, line_end);
4663                 }
4664             }
4665             clipper.End();
4666         }
4667         ImGui::PopStyleVar();
4668 
4669         if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
4670             ImGui::SetScrollHereY(1.0f);
4671 
4672         ImGui::EndChild();
4673         ImGui::End();
4674     }
4675 };
4676 
4677 // Demonstrate creating a simple log window with basic filtering.
ShowExampleAppLog(bool * p_open)4678 static void ShowExampleAppLog(bool* p_open)
4679 {
4680     static ExampleAppLog log;
4681 
4682     // For the demo: add a debug button _BEFORE_ the normal log window contents
4683     // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
4684     // Most of the contents of the window will be added by the log.Draw() call.
4685     ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
4686     ImGui::Begin("Example: Log", p_open);
4687     if (ImGui::SmallButton("[Debug] Add 5 entries"))
4688     {
4689         static int counter = 0;
4690         const char* categories[3] = { "info", "warn", "error" };
4691         const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
4692         for (int n = 0; n < 5; n++)
4693         {
4694             const char* category = categories[counter % IM_ARRAYSIZE(categories)];
4695             const char* word = words[counter % IM_ARRAYSIZE(words)];
4696             log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
4697                 ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
4698             counter++;
4699         }
4700     }
4701     ImGui::End();
4702 
4703     // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
4704     log.Draw("Example: Log", p_open);
4705 }
4706 
4707 //-----------------------------------------------------------------------------
4708 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
4709 //-----------------------------------------------------------------------------
4710 
4711 // Demonstrate create a window with multiple child windows.
ShowExampleAppLayout(bool * p_open)4712 static void ShowExampleAppLayout(bool* p_open)
4713 {
4714     ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
4715     if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
4716     {
4717         if (ImGui::BeginMenuBar())
4718         {
4719             if (ImGui::BeginMenu("File"))
4720             {
4721                 if (ImGui::MenuItem("Close")) *p_open = false;
4722                 ImGui::EndMenu();
4723             }
4724             ImGui::EndMenuBar();
4725         }
4726 
4727         // Left
4728         static int selected = 0;
4729         {
4730             ImGui::BeginChild("left pane", ImVec2(150, 0), true);
4731             for (int i = 0; i < 100; i++)
4732             {
4733                 char label[128];
4734                 sprintf(label, "MyObject %d", i);
4735                 if (ImGui::Selectable(label, selected == i))
4736                     selected = i;
4737             }
4738             ImGui::EndChild();
4739         }
4740         ImGui::SameLine();
4741 
4742         // Right
4743         {
4744             ImGui::BeginGroup();
4745             ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
4746             ImGui::Text("MyObject: %d", selected);
4747             ImGui::Separator();
4748             if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
4749             {
4750                 if (ImGui::BeginTabItem("Description"))
4751                 {
4752                     ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
4753                     ImGui::EndTabItem();
4754                 }
4755                 if (ImGui::BeginTabItem("Details"))
4756                 {
4757                     ImGui::Text("ID: 0123456789");
4758                     ImGui::EndTabItem();
4759                 }
4760                 ImGui::EndTabBar();
4761             }
4762             ImGui::EndChild();
4763             if (ImGui::Button("Revert")) {}
4764             ImGui::SameLine();
4765             if (ImGui::Button("Save")) {}
4766             ImGui::EndGroup();
4767         }
4768     }
4769     ImGui::End();
4770 }
4771 
4772 //-----------------------------------------------------------------------------
4773 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
4774 //-----------------------------------------------------------------------------
4775 
ShowPlaceholderObject(const char * prefix,int uid)4776 static void ShowPlaceholderObject(const char* prefix, int uid)
4777 {
4778     // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
4779     ImGui::PushID(uid);
4780     ImGui::AlignTextToFramePadding();   // Text and Tree nodes are less high than framed widgets, here we add vertical spacing to make the tree lines equal high.
4781     bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
4782     ImGui::NextColumn();
4783     ImGui::AlignTextToFramePadding();
4784     ImGui::Text("my sailor is rich");
4785     ImGui::NextColumn();
4786     if (node_open)
4787     {
4788         static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f };
4789         for (int i = 0; i < 8; i++)
4790         {
4791             ImGui::PushID(i); // Use field index as identifier.
4792             if (i < 2)
4793             {
4794                 ShowPlaceholderObject("Child", 424242);
4795             }
4796             else
4797             {
4798                 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well)
4799                 ImGui::AlignTextToFramePadding();
4800                 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet;
4801                 ImGui::TreeNodeEx("Field", flags, "Field_%d", i);
4802                 ImGui::NextColumn();
4803                 ImGui::SetNextItemWidth(-1);
4804                 if (i >= 5)
4805                     ImGui::InputFloat("##value", &placeholder_members[i], 1.0f);
4806                 else
4807                     ImGui::DragFloat("##value", &placeholder_members[i], 0.01f);
4808                 ImGui::NextColumn();
4809             }
4810             ImGui::PopID();
4811         }
4812         ImGui::TreePop();
4813     }
4814     ImGui::PopID();
4815 }
4816 
4817 // Demonstrate create a simple property editor.
ShowExampleAppPropertyEditor(bool * p_open)4818 static void ShowExampleAppPropertyEditor(bool* p_open)
4819 {
4820     ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
4821     if (!ImGui::Begin("Example: Property editor", p_open))
4822     {
4823         ImGui::End();
4824         return;
4825     }
4826 
4827     HelpMarker(
4828         "This example shows how you may implement a property editor using two columns.\n"
4829         "All objects/fields data are dummies here.\n"
4830         "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n"
4831         "your cursor horizontally instead of using the Columns() API.");
4832 
4833     ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
4834     ImGui::Columns(2);
4835     ImGui::Separator();
4836 
4837     // Iterate placeholder objects (all the same data)
4838     for (int obj_i = 0; obj_i < 3; obj_i++)
4839         ShowPlaceholderObject("Object", obj_i);
4840 
4841     ImGui::Columns(1);
4842     ImGui::Separator();
4843     ImGui::PopStyleVar();
4844     ImGui::End();
4845 }
4846 
4847 //-----------------------------------------------------------------------------
4848 // [SECTION] Example App: Long Text / ShowExampleAppLongText()
4849 //-----------------------------------------------------------------------------
4850 
4851 // Demonstrate/test rendering huge amount of text, and the incidence of clipping.
ShowExampleAppLongText(bool * p_open)4852 static void ShowExampleAppLongText(bool* p_open)
4853 {
4854     ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
4855     if (!ImGui::Begin("Example: Long text display", p_open))
4856     {
4857         ImGui::End();
4858         return;
4859     }
4860 
4861     static int test_type = 0;
4862     static ImGuiTextBuffer log;
4863     static int lines = 0;
4864     ImGui::Text("Printing unusually long amount of text.");
4865     ImGui::Combo("Test type", &test_type,
4866         "Single call to TextUnformatted()\0"
4867         "Multiple calls to Text(), clipped\0"
4868         "Multiple calls to Text(), not clipped (slow)\0");
4869     ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
4870     if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
4871     ImGui::SameLine();
4872     if (ImGui::Button("Add 1000 lines"))
4873     {
4874         for (int i = 0; i < 1000; i++)
4875             log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
4876         lines += 1000;
4877     }
4878     ImGui::BeginChild("Log");
4879     switch (test_type)
4880     {
4881     case 0:
4882         // Single call to TextUnformatted() with a big buffer
4883         ImGui::TextUnformatted(log.begin(), log.end());
4884         break;
4885     case 1:
4886         {
4887             // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
4888             ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
4889             ImGuiListClipper clipper(lines);
4890             while (clipper.Step())
4891                 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
4892                     ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
4893             ImGui::PopStyleVar();
4894             break;
4895         }
4896     case 2:
4897         // Multiple calls to Text(), not clipped (slow)
4898         ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
4899         for (int i = 0; i < lines; i++)
4900             ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
4901         ImGui::PopStyleVar();
4902         break;
4903     }
4904     ImGui::EndChild();
4905     ImGui::End();
4906 }
4907 
4908 //-----------------------------------------------------------------------------
4909 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
4910 //-----------------------------------------------------------------------------
4911 
4912 // Demonstrate creating a window which gets auto-resized according to its content.
ShowExampleAppAutoResize(bool * p_open)4913 static void ShowExampleAppAutoResize(bool* p_open)
4914 {
4915     if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
4916     {
4917         ImGui::End();
4918         return;
4919     }
4920 
4921     static int lines = 10;
4922     ImGui::TextUnformatted(
4923         "Window will resize every-frame to the size of its content.\n"
4924         "Note that you probably don't want to query the window size to\n"
4925         "output your content because that would create a feedback loop.");
4926     ImGui::SliderInt("Number of lines", &lines, 1, 20);
4927     for (int i = 0; i < lines; i++)
4928         ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
4929     ImGui::End();
4930 }
4931 
4932 //-----------------------------------------------------------------------------
4933 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
4934 //-----------------------------------------------------------------------------
4935 
4936 // Demonstrate creating a window with custom resize constraints.
ShowExampleAppConstrainedResize(bool * p_open)4937 static void ShowExampleAppConstrainedResize(bool* p_open)
4938 {
4939     struct CustomConstraints
4940     {
4941         // Helper functions to demonstrate programmatic constraints
4942         static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); }
4943         static void Step(ImGuiSizeCallbackData* data)   { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); }
4944     };
4945 
4946     const char* test_desc[] =
4947     {
4948         "Resize vertical only",
4949         "Resize horizontal only",
4950         "Width > 100, Height > 100",
4951         "Width 400-500",
4952         "Height 400-500",
4953         "Custom: Always Square",
4954         "Custom: Fixed Steps (100)",
4955     };
4956 
4957     static bool auto_resize = false;
4958     static int type = 0;
4959     static int display_lines = 10;
4960     if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0),    ImVec2(-1, FLT_MAX));      // Vertical only
4961     if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1),    ImVec2(FLT_MAX, -1));      // Horizontal only
4962     if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
4963     if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1),  ImVec2(500, -1));          // Width 400-500
4964     if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400),  ImVec2(-1, 500));          // Height 400-500
4965     if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square);                     // Always Square
4966     if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step
4967 
4968     ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
4969     if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
4970     {
4971         if (ImGui::IsWindowDocked())
4972             ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
4973         if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
4974         if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
4975         if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
4976         ImGui::SetNextItemWidth(200);
4977         ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
4978         ImGui::SetNextItemWidth(200);
4979         ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
4980         ImGui::Checkbox("Auto-resize", &auto_resize);
4981         for (int i = 0; i < display_lines; i++)
4982             ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
4983     }
4984     ImGui::End();
4985 }
4986 
4987 //-----------------------------------------------------------------------------
4988 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
4989 //-----------------------------------------------------------------------------
4990 
4991 // Demonstrate creating a simple static window with no decoration
4992 // + a context-menu to choose which corner of the screen to use.
ShowExampleAppSimpleOverlay(bool * p_open)4993 static void ShowExampleAppSimpleOverlay(bool* p_open)
4994 {
4995     // FIXME-VIEWPORT: Select a default viewport
4996     const float DISTANCE = 10.0f;
4997     static int corner = 0;
4998     ImGuiIO& io = ImGui::GetIO();
4999     if (corner != -1)
5000     {
5001         ImGuiViewport* viewport = ImGui::GetMainViewport();
5002         ImVec2 work_area_pos = viewport->GetWorkPos();   // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any!
5003         ImVec2 work_area_size = viewport->GetWorkSize();
5004         ImVec2 window_pos = ImVec2((corner & 1) ? (work_area_pos.x + work_area_size.x - DISTANCE) : (work_area_pos.x + DISTANCE), (corner & 2) ? (work_area_pos.y + work_area_size.y - DISTANCE) : (work_area_pos.y + DISTANCE));
5005         ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
5006         ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
5007         ImGui::SetNextWindowViewport(viewport->ID);
5008     }
5009     ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
5010     ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
5011     if (corner != -1)
5012         window_flags |= ImGuiWindowFlags_NoMove;
5013     if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
5014     {
5015         ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
5016         ImGui::Separator();
5017         if (ImGui::IsMousePosValid())
5018             ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
5019         else
5020             ImGui::Text("Mouse Position: <invalid>");
5021         if (ImGui::BeginPopupContextWindow())
5022         {
5023             if (ImGui::MenuItem("Custom",       NULL, corner == -1)) corner = -1;
5024             if (ImGui::MenuItem("Top-left",     NULL, corner == 0)) corner = 0;
5025             if (ImGui::MenuItem("Top-right",    NULL, corner == 1)) corner = 1;
5026             if (ImGui::MenuItem("Bottom-left",  NULL, corner == 2)) corner = 2;
5027             if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3;
5028             if (p_open && ImGui::MenuItem("Close")) *p_open = false;
5029             ImGui::EndPopup();
5030         }
5031     }
5032     ImGui::End();
5033 }
5034 
5035 //-----------------------------------------------------------------------------
5036 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
5037 //-----------------------------------------------------------------------------
5038 
5039 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation.
5040 // This apply to all regular items as well.
5041 // Read FAQ section "How can I have multiple widgets with the same label?" for details.
ShowExampleAppWindowTitles(bool *)5042 static void ShowExampleAppWindowTitles(bool*)
5043 {
5044     // By default, Windows are uniquely identified by their title.
5045     // You can use the "##" and "###" markers to manipulate the display/ID.
5046 
5047     // Using "##" to display same title but have unique identifier.
5048     ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
5049     ImGui::Begin("Same title as another window##1");
5050     ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
5051     ImGui::End();
5052 
5053     ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver);
5054     ImGui::Begin("Same title as another window##2");
5055     ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
5056     ImGui::End();
5057 
5058     // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
5059     char buf[128];
5060     sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
5061     ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver);
5062     ImGui::Begin(buf);
5063     ImGui::Text("This window has a changing title.");
5064     ImGui::End();
5065 }
5066 
5067 //-----------------------------------------------------------------------------
5068 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
5069 //-----------------------------------------------------------------------------
5070 
5071 // Demonstrate using the low-level ImDrawList to draw custom shapes.
ShowExampleAppCustomRendering(bool * p_open)5072 static void ShowExampleAppCustomRendering(bool* p_open)
5073 {
5074     if (!ImGui::Begin("Example: Custom rendering", p_open))
5075     {
5076         ImGui::End();
5077         return;
5078     }
5079 
5080     // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
5081     // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
5082     // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
5083     // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
5084 
5085     if (ImGui::BeginTabBar("##TabBar"))
5086     {
5087         if (ImGui::BeginTabItem("Primitives"))
5088         {
5089             ImGui::PushItemWidth(-ImGui::GetFontSize() * 10);
5090             ImDrawList* draw_list = ImGui::GetWindowDrawList();
5091 
5092             // Draw gradients
5093             // (note that those are currently exacerbating our sRGB/Linear issues)
5094             // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
5095             ImGui::Text("Gradients");
5096             ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
5097             {
5098                 ImVec2 p0 = ImGui::GetCursorScreenPos();
5099                 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
5100                 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
5101                 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
5102                 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
5103                 ImGui::InvisibleButton("##gradient1", gradient_size);
5104             }
5105             {
5106                 ImVec2 p0 = ImGui::GetCursorScreenPos();
5107                 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
5108                 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
5109                 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
5110                 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
5111                 ImGui::InvisibleButton("##gradient2", gradient_size);
5112             }
5113 
5114             // Draw a bunch of primitives
5115             ImGui::Text("All primitives");
5116             static float sz = 36.0f;
5117             static float thickness = 3.0f;
5118             static int ngon_sides = 6;
5119             static bool circle_segments_override = false;
5120             static int circle_segments_override_v = 12;
5121             static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
5122             ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
5123             ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
5124             ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
5125             ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
5126             ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
5127             if (ImGui::SliderInt("Circle segments", &circle_segments_override_v, 3, 40))
5128                 circle_segments_override = true;
5129             ImGui::ColorEdit4("Color", &colf.x);
5130 
5131             const ImVec2 p = ImGui::GetCursorScreenPos();
5132             const ImU32 col = ImColor(colf);
5133             const float spacing = 10.0f;
5134             const ImDrawCornerFlags corners_none = 0;
5135             const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All;
5136             const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight;
5137             const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
5138             float x = p.x + 4.0f;
5139             float y = p.y + 4.0f;
5140             for (int n = 0; n < 2; n++)
5141             {
5142                 // First line uses a thickness of 1.0f, second line uses the configurable thickness
5143                 float th = (n == 0) ? 1.0f : thickness;
5144                 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th);                 x += sz + spacing;  // N-gon
5145                 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th);          x += sz + spacing;  // Circle
5146                 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f,  corners_none, th);             x += sz + spacing;  // Square
5147                 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th);              x += sz + spacing;  // Square with all rounded corners
5148                 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th);            x += sz + spacing;  // Square with two rounded corners
5149                 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
5150                 //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
5151                 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!)
5152                 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th);                                       x += spacing;       // Vertical line (note: drawing a filled rectangle will be faster!)
5153                 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th);                                  x += sz + spacing;  // Diagonal line
5154                 draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th);
5155                 x = p.x + 4;
5156                 y += sz + spacing;
5157             }
5158             draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides);               x += sz + spacing;  // N-gon
5159             draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments);            x += sz + spacing;  // Circle
5160             draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col);                                    x += sz + spacing;  // Square
5161             draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f);                             x += sz + spacing;  // Square with all rounded corners
5162             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
5163             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
5164             //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
5165             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)
5166             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)
5167             draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col);                                      x += sz;            // Pixel (faster than AddLine)
5168             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));
5169 
5170             ImGui::Dummy(ImVec2((sz + spacing) * 8.8f, (sz + spacing) * 3.0f));
5171             ImGui::PopItemWidth();
5172             ImGui::EndTabItem();
5173         }
5174 
5175         if (ImGui::BeginTabItem("Canvas"))
5176         {
5177             static ImVector<ImVec2> points;
5178             static ImVec2 scrolling(0.0f, 0.0f);
5179             static bool opt_enable_grid = true;
5180             static bool opt_enable_context_menu = true;
5181             static bool adding_line = false;
5182 
5183             ImGui::Checkbox("Enable grid", &opt_enable_grid);
5184             ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
5185             ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
5186 
5187             // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
5188             // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
5189             // To use a child window instead we could use, e.g:
5190             //      ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));      // Disable padding
5191             //      ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255));  // Set a background color
5192             //      ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove);
5193             //      ImGui::PopStyleColor();
5194             //      ImGui::PopStyleVar();
5195             //      [...]
5196             //      ImGui::EndChild();
5197 
5198             // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
5199             ImVec2 canvas_p0 = ImGui::GetCursorScreenPos();      // ImDrawList API uses screen coordinates!
5200             ImVec2 canvas_sz = ImGui::GetContentRegionAvail();   // Resize canvas to what's available
5201             if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
5202             if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
5203             ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
5204 
5205             // Draw border and background color
5206             ImGuiIO& io = ImGui::GetIO();
5207             ImDrawList* draw_list = ImGui::GetWindowDrawList();
5208             draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
5209             draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
5210 
5211             // This will catch our interactions
5212             ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
5213             const bool is_hovered = ImGui::IsItemHovered(); // Hovered
5214             const bool is_active = ImGui::IsItemActive();   // Held
5215             const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
5216             const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
5217 
5218             // Add first and second point
5219             if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
5220             {
5221                 points.push_back(mouse_pos_in_canvas);
5222                 points.push_back(mouse_pos_in_canvas);
5223                 adding_line = true;
5224             }
5225             if (adding_line)
5226             {
5227                 points.back() = mouse_pos_in_canvas;
5228                 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
5229                     adding_line = false;
5230             }
5231 
5232             // Pan (we use a zero mouse threshold when there's no context menu)
5233             // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
5234             const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
5235             if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
5236             {
5237                 scrolling.x += io.MouseDelta.x;
5238                 scrolling.y += io.MouseDelta.y;
5239             }
5240 
5241             // Context menu (under default mouse threshold)
5242             ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
5243             if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
5244                 ImGui::OpenPopupContextItem("context");
5245             if (ImGui::BeginPopup("context"))
5246             {
5247                 if (adding_line)
5248                     points.resize(points.size() - 2);
5249                 adding_line = false;
5250                 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
5251                 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
5252                 ImGui::EndPopup();
5253             }
5254 
5255             // Draw grid + all lines in the canvas
5256             draw_list->PushClipRect(canvas_p0, canvas_p1, true);
5257             if (opt_enable_grid)
5258             {
5259                 const float GRID_STEP = 64.0f;
5260                 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
5261                     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));
5262                 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
5263                     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));
5264             }
5265             for (int n = 0; n < points.Size; n += 2)
5266                 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);
5267             draw_list->PopClipRect();
5268 
5269             ImGui::EndTabItem();
5270         }
5271 
5272         if (ImGui::BeginTabItem("BG/FG draw lists"))
5273         {
5274             static bool draw_bg = true;
5275             static bool draw_fg = true;
5276             ImGui::Checkbox("Draw in Background draw list", &draw_bg);
5277             ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
5278             ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
5279             ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
5280             ImVec2 window_pos = ImGui::GetWindowPos();
5281             ImVec2 window_size = ImGui::GetWindowSize();
5282             ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
5283             if (draw_bg)
5284                 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
5285             if (draw_fg)
5286                 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
5287             ImGui::EndTabItem();
5288         }
5289 
5290         ImGui::EndTabBar();
5291     }
5292 
5293     ImGui::End();
5294 }
5295 
5296 //-----------------------------------------------------------------------------
5297 // [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
5298 //-----------------------------------------------------------------------------
5299 
5300 // Demonstrate using DockSpace() to create an explicit docking node within an existing window.
5301 // Note that you already dock windows into each others _without_ a DockSpace() by just moving windows
5302 // from their title bar (or by holding SHIFT if io.ConfigDockingWithShift is set).
5303 // DockSpace() is only useful to construct to a central location for your application.
ShowExampleAppDockSpace(bool * p_open)5304 void ShowExampleAppDockSpace(bool* p_open)
5305 {
5306     static bool opt_fullscreen = true;
5307     static bool opt_padding = false;
5308     static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
5309 
5310     // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
5311     // because it would be confusing to have two docking targets within each others.
5312     ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
5313     if (opt_fullscreen)
5314     {
5315         ImGuiViewport* viewport = ImGui::GetMainViewport();
5316         ImGui::SetNextWindowPos(viewport->GetWorkPos());
5317         ImGui::SetNextWindowSize(viewport->GetWorkSize());
5318         ImGui::SetNextWindowViewport(viewport->ID);
5319         ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
5320         ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
5321         window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
5322         window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
5323     }
5324     else
5325     {
5326         dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
5327     }
5328 
5329     // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
5330     // and handle the pass-thru hole, so we ask Begin() to not render a background.
5331     if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
5332         window_flags |= ImGuiWindowFlags_NoBackground;
5333 
5334     // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
5335     // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
5336     // all active windows docked into it will lose their parent and become undocked.
5337     // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
5338     // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
5339     if (!opt_padding)
5340         ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
5341     ImGui::Begin("DockSpace Demo", p_open, window_flags);
5342     if (!opt_padding)
5343         ImGui::PopStyleVar();
5344 
5345     if (opt_fullscreen)
5346         ImGui::PopStyleVar(2);
5347 
5348     // DockSpace
5349     ImGuiIO& io = ImGui::GetIO();
5350     if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
5351     {
5352         ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
5353         ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
5354     }
5355     else
5356     {
5357         ShowDockingDisabledMessage();
5358     }
5359 
5360     if (ImGui::BeginMenuBar())
5361     {
5362         if (ImGui::BeginMenu("Options"))
5363         {
5364             // Disabling fullscreen would allow the window to be moved to the front of other windows,
5365             // which we can't undo at the moment without finer window depth/z control.
5366             ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
5367             ImGui::MenuItem("Padding", NULL, &opt_padding);
5368             ImGui::Separator();
5369 
5370             if (ImGui::MenuItem("Flag: NoSplit",                "", (dockspace_flags & ImGuiDockNodeFlags_NoSplit) != 0))                 { dockspace_flags ^= ImGuiDockNodeFlags_NoSplit; }
5371             if (ImGui::MenuItem("Flag: NoResize",               "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0))                { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
5372             if (ImGui::MenuItem("Flag: NoDockingInCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0))  { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode; }
5373             if (ImGui::MenuItem("Flag: AutoHideTabBar",         "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0))          { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
5374             if (ImGui::MenuItem("Flag: PassthruCentralNode",    "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
5375             ImGui::Separator();
5376 
5377             if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
5378                 *p_open = false;
5379             ImGui::EndMenu();
5380         }
5381         HelpMarker(
5382             "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n\n"
5383             " > if io.ConfigDockingWithShift==false (default):" "\n"
5384             "   drag windows from title bar to dock" "\n"
5385             " > if io.ConfigDockingWithShift==true:" "\n"
5386             "   drag windows from anywhere and hold Shift to dock" "\n\n"
5387             "This demo app has nothing to do with it!" "\n\n"
5388             "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n"
5389             "ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n"
5390             "(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)"
5391         );
5392 
5393         ImGui::EndMenuBar();
5394     }
5395 
5396     ImGui::End();
5397 }
5398 
5399 //-----------------------------------------------------------------------------
5400 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
5401 //-----------------------------------------------------------------------------
5402 
5403 // Simplified structure to mimic a Document model
5404 struct MyDocument
5405 {
5406     const char* Name;       // Document title
5407     bool        Open;       // Set when open (we keep an array of all available documents to simplify demo code!)
5408     bool        OpenPrev;   // Copy of Open from last update.
5409     bool        Dirty;      // Set when the document has been modified
5410     bool        WantClose;  // Set when the document
5411     ImVec4      Color;      // An arbitrary variable associated to the document
5412 
MyDocumentMyDocument5413     MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
5414     {
5415         Name = name;
5416         Open = OpenPrev = open;
5417         Dirty = false;
5418         WantClose = false;
5419         Color = color;
5420     }
DoOpenMyDocument5421     void DoOpen()       { Open = true; }
DoQueueCloseMyDocument5422     void DoQueueClose() { WantClose = true; }
DoForceCloseMyDocument5423     void DoForceClose() { Open = false; Dirty = false; }
DoSaveMyDocument5424     void DoSave()       { Dirty = false; }
5425 
5426     // Display placeholder contents for the Document
DisplayContentsMyDocument5427     static void DisplayContents(MyDocument* doc)
5428     {
5429         ImGui::PushID(doc);
5430         ImGui::Text("Document \"%s\"", doc->Name);
5431         ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
5432         ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
5433         ImGui::PopStyleColor();
5434         if (ImGui::Button("Modify", ImVec2(100, 0)))
5435             doc->Dirty = true;
5436         ImGui::SameLine();
5437         if (ImGui::Button("Save", ImVec2(100, 0)))
5438             doc->DoSave();
5439         ImGui::ColorEdit3("color", &doc->Color.x);  // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
5440         ImGui::PopID();
5441     }
5442 
5443     // Display context menu for the Document
DisplayContextMenuMyDocument5444     static void DisplayContextMenu(MyDocument* doc)
5445     {
5446         if (!ImGui::BeginPopupContextItem())
5447             return;
5448 
5449         char buf[256];
5450         sprintf(buf, "Save %s", doc->Name);
5451         if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open))
5452             doc->DoSave();
5453         if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open))
5454             doc->DoQueueClose();
5455         ImGui::EndPopup();
5456     }
5457 };
5458 
5459 struct ExampleAppDocuments
5460 {
5461     ImVector<MyDocument> Documents;
5462 
ExampleAppDocumentsExampleAppDocuments5463     ExampleAppDocuments()
5464     {
5465         Documents.push_back(MyDocument("Lettuce",             true,  ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
5466         Documents.push_back(MyDocument("Eggplant",            true,  ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
5467         Documents.push_back(MyDocument("Carrot",              true,  ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
5468         Documents.push_back(MyDocument("Tomato",              false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
5469         Documents.push_back(MyDocument("A Rather Long Title", false));
5470         Documents.push_back(MyDocument("Some Document",       false));
5471     }
5472 };
5473 
5474 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
5475 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
5476 // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
5477 // 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
5478 // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
5479 // give the impression of a flicker for one frame.
5480 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
5481 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments & app)5482 static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
5483 {
5484     for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5485     {
5486         MyDocument* doc = &app.Documents[doc_n];
5487         if (!doc->Open && doc->OpenPrev)
5488             ImGui::SetTabItemClosed(doc->Name);
5489         doc->OpenPrev = doc->Open;
5490     }
5491 }
5492 
ShowExampleAppDocuments(bool * p_open)5493 void ShowExampleAppDocuments(bool* p_open)
5494 {
5495     static ExampleAppDocuments app;
5496 
5497     // Options
5498     enum Target
5499     {
5500         Target_None,
5501         Target_Tab,                 // Create documents as local tab into a local tab bar
5502         Target_DockSpaceAndWindow   // Create documents as regular windows, and create an embedded dockspace
5503     };
5504     static Target opt_target = Target_Tab;
5505     static bool opt_reorderable = true;
5506     static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
5507 
5508     // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
5509     // that we emit gets docked into the same spot as the parent window ("Example: Documents").
5510     // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
5511     // not visible, which in turn would stop submitting the "Eggplant" window.
5512     // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
5513     // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
5514 
5515     bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
5516     if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
5517     {
5518         ImGui::End();
5519         return;
5520     }
5521 
5522     // Menu
5523     if (ImGui::BeginMenuBar())
5524     {
5525         if (ImGui::BeginMenu("File"))
5526         {
5527             int open_count = 0;
5528             for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5529                 open_count += app.Documents[doc_n].Open ? 1 : 0;
5530 
5531             if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
5532             {
5533                 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5534                 {
5535                     MyDocument* doc = &app.Documents[doc_n];
5536                     if (!doc->Open)
5537                         if (ImGui::MenuItem(doc->Name))
5538                             doc->DoOpen();
5539                 }
5540                 ImGui::EndMenu();
5541             }
5542             if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
5543                 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5544                     app.Documents[doc_n].DoQueueClose();
5545             if (ImGui::MenuItem("Exit", "Alt+F4")) {}
5546             ImGui::EndMenu();
5547         }
5548         ImGui::EndMenuBar();
5549     }
5550 
5551     // [Debug] List documents with one checkbox for each
5552     for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5553     {
5554         MyDocument* doc = &app.Documents[doc_n];
5555         if (doc_n > 0)
5556             ImGui::SameLine();
5557         ImGui::PushID(doc);
5558         if (ImGui::Checkbox(doc->Name, &doc->Open))
5559             if (!doc->Open)
5560                 doc->DoForceClose();
5561         ImGui::PopID();
5562     }
5563     ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
5564     ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
5565     ImGui::PopItemWidth();
5566     bool redock_all = false;
5567     if (opt_target == Target_Tab)                { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
5568     if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
5569 
5570     ImGui::Separator();
5571 
5572     // Tabs
5573     if (opt_target == Target_Tab)
5574     {
5575         ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
5576         if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
5577         {
5578             if (opt_reorderable)
5579                 NotifyOfDocumentsClosedElsewhere(app);
5580 
5581             // [DEBUG] Stress tests
5582             //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1;            // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
5583             //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name);  // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
5584 
5585             // Submit Tabs
5586             for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5587             {
5588                 MyDocument* doc = &app.Documents[doc_n];
5589                 if (!doc->Open)
5590                     continue;
5591 
5592                 ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
5593                 bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags);
5594 
5595                 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
5596                 if (!doc->Open && doc->Dirty)
5597                 {
5598                     doc->Open = true;
5599                     doc->DoQueueClose();
5600                 }
5601 
5602                 MyDocument::DisplayContextMenu(doc);
5603                 if (visible)
5604                 {
5605                     MyDocument::DisplayContents(doc);
5606                     ImGui::EndTabItem();
5607                 }
5608             }
5609 
5610             ImGui::EndTabBar();
5611         }
5612     }
5613     else if (opt_target == Target_DockSpaceAndWindow)
5614     {
5615         if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
5616         {
5617             NotifyOfDocumentsClosedElsewhere(app);
5618 
5619             // Create a DockSpace node where any window can be docked
5620             ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
5621             ImGui::DockSpace(dockspace_id);
5622 
5623             // Create Windows
5624             for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5625             {
5626                 MyDocument* doc = &app.Documents[doc_n];
5627                 if (!doc->Open)
5628                     continue;
5629 
5630                 ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
5631                 ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
5632                 bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
5633 
5634                 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
5635                 if (!doc->Open && doc->Dirty)
5636                 {
5637                     doc->Open = true;
5638                     doc->DoQueueClose();
5639                 }
5640 
5641                 MyDocument::DisplayContextMenu(doc);
5642                 if (visible)
5643                     MyDocument::DisplayContents(doc);
5644 
5645                 ImGui::End();
5646             }
5647         }
5648         else
5649         {
5650             ShowDockingDisabledMessage();
5651         }
5652     }
5653 
5654     // Early out other contents
5655     if (!window_contents_visible)
5656     {
5657         ImGui::End();
5658         return;
5659     }
5660 
5661     // Update closing queue
5662     static ImVector<MyDocument*> close_queue;
5663     if (close_queue.empty())
5664     {
5665         // Close queue is locked once we started a popup
5666         for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
5667         {
5668             MyDocument* doc = &app.Documents[doc_n];
5669             if (doc->WantClose)
5670             {
5671                 doc->WantClose = false;
5672                 close_queue.push_back(doc);
5673             }
5674         }
5675     }
5676 
5677     // Display closing confirmation UI
5678     if (!close_queue.empty())
5679     {
5680         int close_queue_unsaved_documents = 0;
5681         for (int n = 0; n < close_queue.Size; n++)
5682             if (close_queue[n]->Dirty)
5683                 close_queue_unsaved_documents++;
5684 
5685         if (close_queue_unsaved_documents == 0)
5686         {
5687             // Close documents when all are unsaved
5688             for (int n = 0; n < close_queue.Size; n++)
5689                 close_queue[n]->DoForceClose();
5690             close_queue.clear();
5691         }
5692         else
5693         {
5694             if (!ImGui::IsPopupOpen("Save?"))
5695                 ImGui::OpenPopup("Save?");
5696             if (ImGui::BeginPopupModal("Save?"))
5697             {
5698                 ImGui::Text("Save change to the following items?");
5699                 ImGui::SetNextItemWidth(-1.0f);
5700                 if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6))
5701                 {
5702                     for (int n = 0; n < close_queue.Size; n++)
5703                         if (close_queue[n]->Dirty)
5704                             ImGui::Text("%s", close_queue[n]->Name);
5705                     ImGui::ListBoxFooter();
5706                 }
5707 
5708                 if (ImGui::Button("Yes", ImVec2(80, 0)))
5709                 {
5710                     for (int n = 0; n < close_queue.Size; n++)
5711                     {
5712                         if (close_queue[n]->Dirty)
5713                             close_queue[n]->DoSave();
5714                         close_queue[n]->DoForceClose();
5715                     }
5716                     close_queue.clear();
5717                     ImGui::CloseCurrentPopup();
5718                 }
5719                 ImGui::SameLine();
5720                 if (ImGui::Button("No", ImVec2(80, 0)))
5721                 {
5722                     for (int n = 0; n < close_queue.Size; n++)
5723                         close_queue[n]->DoForceClose();
5724                     close_queue.clear();
5725                     ImGui::CloseCurrentPopup();
5726                 }
5727                 ImGui::SameLine();
5728                 if (ImGui::Button("Cancel", ImVec2(80, 0)))
5729                 {
5730                     close_queue.clear();
5731                     ImGui::CloseCurrentPopup();
5732                 }
5733                 ImGui::EndPopup();
5734             }
5735         }
5736     }
5737 
5738     ImGui::End();
5739 }
5740 
5741 // End of Demo code
5742 #else
5743 
ShowAboutWindow(bool *)5744 void ImGui::ShowAboutWindow(bool*) {}
ShowDemoWindow(bool *)5745 void ImGui::ShowDemoWindow(bool*) {}
ShowUserGuide()5746 void ImGui::ShowUserGuide() {}
ShowStyleEditor(ImGuiStyle *)5747 void ImGui::ShowStyleEditor(ImGuiStyle*) {}
5748 
5749 #endif
5750 
5751 #endif // #ifndef IMGUI_DISABLE
5752