1 // dear imgui, v1.84 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 the 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 codebase:
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 another 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 use 'static' variables inside functions. A static variable persists 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 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 // Navigating this file:
42 // - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
43 // - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
44
45 /*
46
47 Index of this file:
48
49 // [SECTION] Forward Declarations, Helpers
50 // [SECTION] Demo Window / ShowDemoWindow()
51 // - sub section: ShowDemoWindowWidgets()
52 // - sub section: ShowDemoWindowLayout()
53 // - sub section: ShowDemoWindowPopups()
54 // - sub section: ShowDemoWindowTables()
55 // - sub section: ShowDemoWindowMisc()
56 // [SECTION] About Window / ShowAboutWindow()
57 // [SECTION] Style Editor / ShowStyleEditor()
58 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
59 // [SECTION] Example App: Debug Console / ShowExampleAppConsole()
60 // [SECTION] Example App: Debug Log / ShowExampleAppLog()
61 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
62 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
63 // [SECTION] Example App: Long Text / ShowExampleAppLongText()
64 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
65 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
66 // [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
67 // [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
68 // [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles()
69 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
70 // [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
71 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
72
73 */
74
75 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
76 #define _CRT_SECURE_NO_WARNINGS
77 #endif
78
79 #include "imgui.h"
80 #ifndef IMGUI_DISABLE
81
82 // System includes
83 #include <ctype.h> // toupper
84 #include <limits.h> // INT_MIN, INT_MAX
85 #include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
86 #include <stdio.h> // vsnprintf, sscanf, printf
87 #include <stdlib.h> // NULL, malloc, free, atoi
88 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
89 #include <stddef.h> // intptr_t
90 #else
91 #include <stdint.h> // intptr_t
92 #endif
93
94 // Visual Studio warnings
95 #ifdef _MSC_VER
96 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
97 #pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
98 #endif
99
100 // Clang/GCC warnings with -Weverything
101 #if defined(__clang__)
102 #if __has_warning("-Wunknown-warning-option")
103 #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!
104 #endif
105 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
106 #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
107 #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)
108 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type
109 #pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal
110 #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.
111 #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.
112 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
113 #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.
114 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
115 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
116 #elif defined(__GNUC__)
117 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
118 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
119 #pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure)
120 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
121 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
122 #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.
123 #endif
124
125 // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
126 #ifdef _WIN32
127 #define IM_NEWLINE "\r\n"
128 #else
129 #define IM_NEWLINE "\n"
130 #endif
131
132 // Helpers
133 #if defined(_MSC_VER) && !defined(snprintf)
134 #define snprintf _snprintf
135 #endif
136 #if defined(_MSC_VER) && !defined(vsnprintf)
137 #define vsnprintf _vsnprintf
138 #endif
139
140 // Format specifiers, printing 64-bit hasn't been decently standardized...
141 // In a real application you should be using PRId64 and PRIu64 from <inttypes.h> (non-windows) and on Windows define them yourself.
142 #ifdef _MSC_VER
143 #define IM_PRId64 "I64d"
144 #define IM_PRIu64 "I64u"
145 #else
146 #define IM_PRId64 "lld"
147 #define IM_PRIu64 "llu"
148 #endif
149
150 // Helpers macros
151 // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
152 // but making an exception here as those are largely simplifying code...
153 // In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
154 #define IM_MIN(A, B) (((A) < (B)) ? (A) : (B))
155 #define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B))
156 #define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
157
158 // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall
159 #ifndef IMGUI_CDECL
160 #ifdef _MSC_VER
161 #define IMGUI_CDECL __cdecl
162 #else
163 #define IMGUI_CDECL
164 #endif
165 #endif
166
167 //-----------------------------------------------------------------------------
168 // [SECTION] Forward Declarations, Helpers
169 //-----------------------------------------------------------------------------
170
171 #if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
172
173 // Forward Declarations
174 static void ShowExampleAppDockSpace(bool* p_open);
175 static void ShowExampleAppDocuments(bool* p_open);
176 static void ShowExampleAppMainMenuBar();
177 static void ShowExampleAppConsole(bool* p_open);
178 static void ShowExampleAppLog(bool* p_open);
179 static void ShowExampleAppLayout(bool* p_open);
180 static void ShowExampleAppPropertyEditor(bool* p_open);
181 static void ShowExampleAppLongText(bool* p_open);
182 static void ShowExampleAppAutoResize(bool* p_open);
183 static void ShowExampleAppConstrainedResize(bool* p_open);
184 static void ShowExampleAppSimpleOverlay(bool* p_open);
185 static void ShowExampleAppFullscreen(bool* p_open);
186 static void ShowExampleAppWindowTitles(bool* p_open);
187 static void ShowExampleAppCustomRendering(bool* p_open);
188 static void ShowExampleMenuFile();
189
190 // Helper to display a little (?) mark which shows a tooltip when hovered.
191 // 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)192 static void HelpMarker(const char* desc)
193 {
194 ImGui::TextDisabled("(?)");
195 if (ImGui::IsItemHovered())
196 {
197 ImGui::BeginTooltip();
198 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
199 ImGui::TextUnformatted(desc);
200 ImGui::PopTextWrapPos();
201 ImGui::EndTooltip();
202 }
203 }
204
ShowDockingDisabledMessage()205 static void ShowDockingDisabledMessage()
206 {
207 ImGuiIO& io = ImGui::GetIO();
208 ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration.");
209 ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or ");
210 ImGui::SameLine(0.0f, 0.0f);
211 if (ImGui::SmallButton("click here"))
212 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
213 }
214
215 // Helper to display basic user controls.
ShowUserGuide()216 void ImGui::ShowUserGuide()
217 {
218 ImGuiIO& io = ImGui::GetIO();
219 ImGui::BulletText("Double-click on title bar to collapse window.");
220 ImGui::BulletText(
221 "Click and drag on lower corner to resize window\n"
222 "(double-click to auto fit window to its contents).");
223 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
224 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
225 if (io.FontAllowUserScaling)
226 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
227 ImGui::BulletText("While inputing text:\n");
228 ImGui::Indent();
229 ImGui::BulletText("CTRL+Left/Right to word jump.");
230 ImGui::BulletText("CTRL+A or double-click to select all.");
231 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
232 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
233 ImGui::BulletText("ESCAPE to revert.");
234 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
235 ImGui::Unindent();
236 ImGui::BulletText("With keyboard navigation enabled:");
237 ImGui::Indent();
238 ImGui::BulletText("Arrow keys to navigate.");
239 ImGui::BulletText("Space to activate a widget.");
240 ImGui::BulletText("Return to input text into a widget.");
241 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
242 ImGui::BulletText("Alt to jump to the menu layer of a window.");
243 ImGui::BulletText("CTRL+Tab to select a window.");
244 ImGui::Unindent();
245 }
246
247 //-----------------------------------------------------------------------------
248 // [SECTION] Demo Window / ShowDemoWindow()
249 //-----------------------------------------------------------------------------
250 // - ShowDemoWindowWidgets()
251 // - ShowDemoWindowLayout()
252 // - ShowDemoWindowPopups()
253 // - ShowDemoWindowTables()
254 // - ShowDemoWindowColumns()
255 // - ShowDemoWindowMisc()
256 //-----------------------------------------------------------------------------
257
258 // We split the contents of the big ShowDemoWindow() function into smaller functions
259 // (because the link time of very large functions grow non-linearly)
260 static void ShowDemoWindowWidgets();
261 static void ShowDemoWindowLayout();
262 static void ShowDemoWindowPopups();
263 static void ShowDemoWindowTables();
264 static void ShowDemoWindowColumns();
265 static void ShowDemoWindowMisc();
266
267 // Demonstrate most Dear ImGui features (this is big function!)
268 // You may execute this function to experiment with the UI and understand what it does.
269 // You may then search for keywords in the code when you are interested by a specific feature.
ShowDemoWindow(bool * p_open)270 void ImGui::ShowDemoWindow(bool* p_open)
271 {
272 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
273 // Most ImGui functions would normally just crash if the context is missing.
274 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!");
275
276 // Examples Apps (accessible from the "Examples" menu)
277 static bool show_app_main_menu_bar = false;
278 static bool show_app_dockspace = false;
279 static bool show_app_documents = false;
280
281 static bool show_app_console = false;
282 static bool show_app_log = false;
283 static bool show_app_layout = false;
284 static bool show_app_property_editor = false;
285 static bool show_app_long_text = false;
286 static bool show_app_auto_resize = false;
287 static bool show_app_constrained_resize = false;
288 static bool show_app_simple_overlay = false;
289 static bool show_app_fullscreen = false;
290 static bool show_app_window_titles = false;
291 static bool show_app_custom_rendering = false;
292
293 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
294 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)
295 if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
296
297 if (show_app_console) ShowExampleAppConsole(&show_app_console);
298 if (show_app_log) ShowExampleAppLog(&show_app_log);
299 if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
300 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
301 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
302 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
303 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
304 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
305 if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen);
306 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
307 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
308
309 // Dear ImGui Apps (accessible from the "Tools" menu)
310 static bool show_app_metrics = false;
311 static bool show_app_style_editor = false;
312 static bool show_app_about = false;
313
314 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); }
315 if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); }
316 if (show_app_style_editor)
317 {
318 ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor);
319 ImGui::ShowStyleEditor();
320 ImGui::End();
321 }
322
323 // Demonstrate the various window flags. Typically you would just use the default!
324 static bool no_titlebar = false;
325 static bool no_scrollbar = false;
326 static bool no_menu = false;
327 static bool no_move = false;
328 static bool no_resize = false;
329 static bool no_collapse = false;
330 static bool no_close = false;
331 static bool no_nav = false;
332 static bool no_background = false;
333 static bool no_bring_to_front = false;
334 static bool no_docking = false;
335 static bool unsaved_document = false;
336
337 ImGuiWindowFlags window_flags = 0;
338 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
339 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
340 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
341 if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
342 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
343 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
344 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
345 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
346 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
347 if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
348 if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument;
349 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
350
351 // We specify a default position/size in case there's no data in the .ini file.
352 // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
353 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
354 ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + 650, main_viewport->WorkPos.y + 20), ImGuiCond_FirstUseEver);
355 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
356
357 // Main body of the Demo window starts here.
358 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
359 {
360 // Early out if the window is collapsed, as an optimization.
361 ImGui::End();
362 return;
363 }
364
365 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
366
367 // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
368 //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f);
369
370 // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
371 ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
372
373 // Menu Bar
374 if (ImGui::BeginMenuBar())
375 {
376 if (ImGui::BeginMenu("Menu"))
377 {
378 ShowExampleMenuFile();
379 ImGui::EndMenu();
380 }
381 if (ImGui::BeginMenu("Examples"))
382 {
383 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
384 ImGui::MenuItem("Console", NULL, &show_app_console);
385 ImGui::MenuItem("Log", NULL, &show_app_log);
386 ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
387 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
388 ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
389 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
390 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
391 ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
392 ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen);
393 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
394 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
395 ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace);
396 ImGui::MenuItem("Documents", NULL, &show_app_documents);
397 ImGui::EndMenu();
398 }
399 if (ImGui::BeginMenu("Tools"))
400 {
401 ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics);
402 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
403 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
404 ImGui::EndMenu();
405 }
406 ImGui::EndMenuBar();
407 }
408
409 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION);
410 ImGui::Spacing();
411
412 if (ImGui::CollapsingHeader("Help"))
413 {
414 ImGui::Text("ABOUT THIS DEMO:");
415 ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
416 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
417 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
418 "and Metrics/Debugger (general purpose Dear ImGui debugging tool).");
419 ImGui::Separator();
420
421 ImGui::Text("PROGRAMMER GUIDE:");
422 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
423 ImGui::BulletText("See comments in imgui.cpp.");
424 ImGui::BulletText("See example applications in the examples/ folder.");
425 ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/");
426 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
427 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
428 ImGui::Separator();
429
430 ImGui::Text("USER GUIDE:");
431 ImGui::ShowUserGuide();
432 }
433
434 if (ImGui::CollapsingHeader("Configuration"))
435 {
436 ImGuiIO& io = ImGui::GetIO();
437
438 if (ImGui::TreeNode("Configuration##2"))
439 {
440 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
441 ImGui::SameLine(); HelpMarker("Enable keyboard controls.");
442 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
443 ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
444 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
445 ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
446 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
447 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
448 {
449 // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
450 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
451 {
452 ImGui::SameLine();
453 ImGui::Text("<<PRESS SPACE TO DISABLE>>");
454 }
455 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space)))
456 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
457 }
458 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
459 ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
460
461 ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
462 ImGui::SameLine(); HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows).");
463 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
464 {
465 ImGui::Indent();
466 ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit);
467 ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars.");
468 ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
469 ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows.");
470 ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload);
471 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.");
472 ImGui::Unindent();
473 }
474
475 ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
476 ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details.");
477 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
478 {
479 ImGui::Indent();
480 ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge);
481 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.");
482 ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon);
483 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the task bar icon state right away).");
484 ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration);
485 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the decoration right away).");
486 ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent);
487 ImGui::SameLine(); HelpMarker("Toggling this at runtime is normally unsupported (most platform backends won't refresh the parenting right away).");
488 ImGui::Unindent();
489 }
490
491 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
492 ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)");
493 ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText);
494 ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving).");
495 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
496 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.");
497 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
498 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
499 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).");
500 ImGui::Text("Also see Style->Rendering for rendering options.");
501 ImGui::TreePop();
502 ImGui::Separator();
503 }
504
505 if (ImGui::TreeNode("Backend Flags"))
506 {
507 HelpMarker(
508 "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n"
509 "Here we expose then as read-only fields to avoid breaking interactions with your backend.");
510
511 // Make a local copy to avoid modifying actual backend flags.
512 ImGuiBackendFlags backend_flags = io.BackendFlags;
513 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad);
514 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors);
515 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &backend_flags, ImGuiBackendFlags_HasSetMousePos);
516 ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &backend_flags, ImGuiBackendFlags_PlatformHasViewports);
517 ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&backend_flags, ImGuiBackendFlags_HasMouseHoveredViewport);
518 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset);
519 ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &backend_flags, ImGuiBackendFlags_RendererHasViewports);
520 ImGui::TreePop();
521 ImGui::Separator();
522 }
523
524 if (ImGui::TreeNode("Style"))
525 {
526 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
527 ImGui::ShowStyleEditor();
528 ImGui::TreePop();
529 ImGui::Separator();
530 }
531
532 if (ImGui::TreeNode("Capture/Logging"))
533 {
534 HelpMarker(
535 "The logging API redirects all text output so you can easily capture the content of "
536 "a window or a block. Tree nodes can be automatically expanded.\n"
537 "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
538 ImGui::LogButtons();
539
540 HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
541 if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
542 {
543 ImGui::LogToClipboard();
544 ImGui::LogText("Hello, world!");
545 ImGui::LogFinish();
546 }
547 ImGui::TreePop();
548 }
549 }
550
551 if (ImGui::CollapsingHeader("Window options"))
552 {
553 if (ImGui::BeginTable("split", 3))
554 {
555 ImGui::TableNextColumn(); ImGui::Checkbox("No titlebar", &no_titlebar);
556 ImGui::TableNextColumn(); ImGui::Checkbox("No scrollbar", &no_scrollbar);
557 ImGui::TableNextColumn(); ImGui::Checkbox("No menu", &no_menu);
558 ImGui::TableNextColumn(); ImGui::Checkbox("No move", &no_move);
559 ImGui::TableNextColumn(); ImGui::Checkbox("No resize", &no_resize);
560 ImGui::TableNextColumn(); ImGui::Checkbox("No collapse", &no_collapse);
561 ImGui::TableNextColumn(); ImGui::Checkbox("No close", &no_close);
562 ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav);
563 ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background);
564 ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front);
565 ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking);
566 ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document);
567 ImGui::EndTable();
568 }
569 }
570
571 // All demo contents
572 ShowDemoWindowWidgets();
573 ShowDemoWindowLayout();
574 ShowDemoWindowPopups();
575 ShowDemoWindowTables();
576 ShowDemoWindowMisc();
577
578 // End of ShowDemoWindow()
579 ImGui::PopItemWidth();
580 ImGui::End();
581 }
582
ShowDemoWindowWidgets()583 static void ShowDemoWindowWidgets()
584 {
585 if (!ImGui::CollapsingHeader("Widgets"))
586 return;
587
588 if (ImGui::TreeNode("Basic"))
589 {
590 static int clicked = 0;
591 if (ImGui::Button("Button"))
592 clicked++;
593 if (clicked & 1)
594 {
595 ImGui::SameLine();
596 ImGui::Text("Thanks for clicking me!");
597 }
598
599 static bool check = true;
600 ImGui::Checkbox("checkbox", &check);
601
602 static int e = 0;
603 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
604 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
605 ImGui::RadioButton("radio c", &e, 2);
606
607 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
608 for (int i = 0; i < 7; i++)
609 {
610 if (i > 0)
611 ImGui::SameLine();
612 ImGui::PushID(i);
613 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
614 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
615 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
616 ImGui::Button("Click");
617 ImGui::PopStyleColor(3);
618 ImGui::PopID();
619 }
620
621 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
622 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
623 // See 'Demo->Layout->Text Baseline Alignment' for details.
624 ImGui::AlignTextToFramePadding();
625 ImGui::Text("Hold to repeat:");
626 ImGui::SameLine();
627
628 // Arrow buttons with Repeater
629 static int counter = 0;
630 float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
631 ImGui::PushButtonRepeat(true);
632 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
633 ImGui::SameLine(0.0f, spacing);
634 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
635 ImGui::PopButtonRepeat();
636 ImGui::SameLine();
637 ImGui::Text("%d", counter);
638
639 ImGui::Text("Hover over me");
640 if (ImGui::IsItemHovered())
641 ImGui::SetTooltip("I am a tooltip");
642
643 ImGui::SameLine();
644 ImGui::Text("- or me");
645 if (ImGui::IsItemHovered())
646 {
647 ImGui::BeginTooltip();
648 ImGui::Text("I am a fancy tooltip");
649 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
650 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
651 ImGui::EndTooltip();
652 }
653
654 ImGui::Separator();
655
656 ImGui::LabelText("label", "Value");
657
658 {
659 // Using the _simplified_ one-liner Combo() api here
660 // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
661 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
662 static int item_current = 0;
663 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
664 ImGui::SameLine(); HelpMarker(
665 "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
666 }
667
668 {
669 // To wire InputText() with std::string or any other custom string type,
670 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
671 static char str0[128] = "Hello, world!";
672 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
673 ImGui::SameLine(); HelpMarker(
674 "USER:\n"
675 "Hold SHIFT or use mouse to select text.\n"
676 "CTRL+Left/Right to word jump.\n"
677 "CTRL+A or double-click to select all.\n"
678 "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
679 "CTRL+Z,CTRL+Y undo/redo.\n"
680 "ESCAPE to revert.\n\n"
681 "PROGRAMMER:\n"
682 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
683 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
684 "in imgui_demo.cpp).");
685
686 static char str1[128] = "";
687 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
688
689 static int i0 = 123;
690 ImGui::InputInt("input int", &i0);
691 ImGui::SameLine(); HelpMarker(
692 "You can apply arithmetic operators +,*,/ on numerical values.\n"
693 " e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n"
694 "Use +- to subtract.");
695
696 static float f0 = 0.001f;
697 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
698
699 static double d0 = 999999.00000001;
700 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
701
702 static float f1 = 1.e10f;
703 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
704 ImGui::SameLine(); HelpMarker(
705 "You can input value using the scientific notation,\n"
706 " e.g. \"1e+8\" becomes \"100000000\".");
707
708 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
709 ImGui::InputFloat3("input float3", vec4a);
710 }
711
712 {
713 static int i1 = 50, i2 = 42;
714 ImGui::DragInt("drag int", &i1, 1);
715 ImGui::SameLine(); HelpMarker(
716 "Click and drag to edit value.\n"
717 "Hold SHIFT/ALT for faster/slower edit.\n"
718 "Double-click or CTRL+click to input value.");
719
720 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
721
722 static float f1 = 1.00f, f2 = 0.0067f;
723 ImGui::DragFloat("drag float", &f1, 0.005f);
724 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
725 }
726
727 {
728 static int i1 = 0;
729 ImGui::SliderInt("slider int", &i1, -1, 3);
730 ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
731
732 static float f1 = 0.123f, f2 = 0.0f;
733 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
734 ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
735
736 static float angle = 0.0f;
737 ImGui::SliderAngle("slider angle", &angle);
738
739 // Using the format string to display a name instead of an integer.
740 // Here we completely omit '%d' from the format string, so it'll only display a name.
741 // This technique can also be used with DragInt().
742 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
743 static int elem = Element_Fire;
744 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
745 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
746 ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name);
747 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
748 }
749
750 {
751 static float col1[3] = { 1.0f, 0.0f, 0.2f };
752 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
753 ImGui::ColorEdit3("color 1", col1);
754 ImGui::SameLine(); HelpMarker(
755 "Click on the color square to open a color picker.\n"
756 "Click and hold to use drag and drop.\n"
757 "Right-click on the color square to show options.\n"
758 "CTRL+click on individual component to input value.\n");
759
760 ImGui::ColorEdit4("color 2", col2);
761 }
762
763 {
764 // Using the _simplified_ one-liner ListBox() api here
765 // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
766 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
767 static int item_current = 1;
768 ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4);
769 ImGui::SameLine(); HelpMarker(
770 "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
771 }
772
773 ImGui::TreePop();
774 }
775
776 // Testing ImGuiOnceUponAFrame helper.
777 //static ImGuiOnceUponAFrame once;
778 //for (int i = 0; i < 5; i++)
779 // if (once)
780 // ImGui::Text("This will be displayed only once.");
781
782 if (ImGui::TreeNode("Trees"))
783 {
784 if (ImGui::TreeNode("Basic trees"))
785 {
786 for (int i = 0; i < 5; i++)
787 {
788 // Use SetNextItemOpen() so set the default state of a node to be open. We could
789 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
790 if (i == 0)
791 ImGui::SetNextItemOpen(true, ImGuiCond_Once);
792
793 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
794 {
795 ImGui::Text("blah blah");
796 ImGui::SameLine();
797 if (ImGui::SmallButton("button")) {}
798 ImGui::TreePop();
799 }
800 }
801 ImGui::TreePop();
802 }
803
804 if (ImGui::TreeNode("Advanced, with Selectable nodes"))
805 {
806 HelpMarker(
807 "This is a more typical looking tree with selectable nodes.\n"
808 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
809 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
810 static bool align_label_with_current_x_position = false;
811 static bool test_drag_and_drop = false;
812 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
813 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
814 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
815 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
816 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
817 ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
818 ImGui::Text("Hello!");
819 if (align_label_with_current_x_position)
820 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
821
822 // 'selection_mask' is dumb representation of what may be user-side selection state.
823 // You may retain selection state inside or outside your objects in whatever format you see fit.
824 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
825 /// of the loop. May be a pointer to your own node type, etc.
826 static int selection_mask = (1 << 2);
827 int node_clicked = -1;
828 for (int i = 0; i < 6; i++)
829 {
830 // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
831 ImGuiTreeNodeFlags node_flags = base_flags;
832 const bool is_selected = (selection_mask & (1 << i)) != 0;
833 if (is_selected)
834 node_flags |= ImGuiTreeNodeFlags_Selected;
835 if (i < 3)
836 {
837 // Items 0..2 are Tree Node
838 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
839 if (ImGui::IsItemClicked())
840 node_clicked = i;
841 if (test_drag_and_drop && ImGui::BeginDragDropSource())
842 {
843 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
844 ImGui::Text("This is a drag and drop source");
845 ImGui::EndDragDropSource();
846 }
847 if (node_open)
848 {
849 ImGui::BulletText("Blah blah\nBlah Blah");
850 ImGui::TreePop();
851 }
852 }
853 else
854 {
855 // Items 3..5 are Tree Leaves
856 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
857 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
858 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
859 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
860 if (ImGui::IsItemClicked())
861 node_clicked = i;
862 if (test_drag_and_drop && ImGui::BeginDragDropSource())
863 {
864 ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
865 ImGui::Text("This is a drag and drop source");
866 ImGui::EndDragDropSource();
867 }
868 }
869 }
870 if (node_clicked != -1)
871 {
872 // Update selection state
873 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
874 if (ImGui::GetIO().KeyCtrl)
875 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
876 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
877 selection_mask = (1 << node_clicked); // Click to single-select
878 }
879 if (align_label_with_current_x_position)
880 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
881 ImGui::TreePop();
882 }
883 ImGui::TreePop();
884 }
885
886 if (ImGui::TreeNode("Collapsing Headers"))
887 {
888 static bool closable_group = true;
889 ImGui::Checkbox("Show 2nd header", &closable_group);
890 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
891 {
892 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
893 for (int i = 0; i < 5; i++)
894 ImGui::Text("Some content %d", i);
895 }
896 if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
897 {
898 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
899 for (int i = 0; i < 5; i++)
900 ImGui::Text("More content %d", i);
901 }
902 /*
903 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
904 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
905 */
906 ImGui::TreePop();
907 }
908
909 if (ImGui::TreeNode("Bullets"))
910 {
911 ImGui::BulletText("Bullet point 1");
912 ImGui::BulletText("Bullet point 2\nOn multiple lines");
913 if (ImGui::TreeNode("Tree node"))
914 {
915 ImGui::BulletText("Another bullet point");
916 ImGui::TreePop();
917 }
918 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
919 ImGui::Bullet(); ImGui::SmallButton("Button");
920 ImGui::TreePop();
921 }
922
923 if (ImGui::TreeNode("Text"))
924 {
925 if (ImGui::TreeNode("Colorful Text"))
926 {
927 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
928 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
929 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
930 ImGui::TextDisabled("Disabled");
931 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
932 ImGui::TreePop();
933 }
934
935 if (ImGui::TreeNode("Word Wrapping"))
936 {
937 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
938 ImGui::TextWrapped(
939 "This text should automatically wrap on the edge of the window. The current implementation "
940 "for text wrapping follows simple rules suitable for English and possibly other languages.");
941 ImGui::Spacing();
942
943 static float wrap_width = 200.0f;
944 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
945
946 ImDrawList* draw_list = ImGui::GetWindowDrawList();
947 for (int n = 0; n < 2; n++)
948 {
949 ImGui::Text("Test paragraph %d:", n);
950 ImVec2 pos = ImGui::GetCursorScreenPos();
951 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
952 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
953 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
954 if (n == 0)
955 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);
956 else
957 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
958
959 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
960 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
961 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
962 ImGui::PopTextWrapPos();
963 }
964
965 ImGui::TreePop();
966 }
967
968 if (ImGui::TreeNode("UTF-8 Text"))
969 {
970 // UTF-8 test with Japanese characters
971 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
972 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
973 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
974 // can save your source files as 'UTF-8 without signature').
975 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
976 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
977 // Don't do this in your application! Please use u8"text in any language" in your application!
978 // Note that characters values are preserved even by InputText() if the font cannot be displayed,
979 // so you can safely copy & paste garbled characters into another application.
980 ImGui::TextWrapped(
981 "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. "
982 "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. "
983 "Read docs/FONTS.md for details.");
984 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.
985 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
986 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
987 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
988 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
989 ImGui::TreePop();
990 }
991 ImGui::TreePop();
992 }
993
994 if (ImGui::TreeNode("Images"))
995 {
996 ImGuiIO& io = ImGui::GetIO();
997 ImGui::TextWrapped(
998 "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
999 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
1000 "Hover the texture for a zoomed view!");
1001
1002 // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
1003 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
1004 // will be passed to the rendering backend via the ImDrawCmd structure.
1005 // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top
1006 // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
1007 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
1008 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
1009 // More:
1010 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
1011 // to ImGui::Image(), and gather width/height through your own functions, etc.
1012 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
1013 // it will help you debug issues if you are confused about it.
1014 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
1015 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
1016 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
1017 ImTextureID my_tex_id = io.Fonts->TexID;
1018 float my_tex_w = (float)io.Fonts->TexWidth;
1019 float my_tex_h = (float)io.Fonts->TexHeight;
1020 {
1021 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
1022 ImVec2 pos = ImGui::GetCursorScreenPos();
1023 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
1024 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
1025 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1026 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white
1027 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
1028 if (ImGui::IsItemHovered())
1029 {
1030 ImGui::BeginTooltip();
1031 float region_sz = 32.0f;
1032 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
1033 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
1034 float zoom = 4.0f;
1035 if (region_x < 0.0f) { region_x = 0.0f; }
1036 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
1037 if (region_y < 0.0f) { region_y = 0.0f; }
1038 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
1039 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
1040 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
1041 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
1042 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
1043 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
1044 ImGui::EndTooltip();
1045 }
1046 }
1047 ImGui::TextWrapped("And now some textured buttons..");
1048 static int pressed_count = 0;
1049 for (int i = 0; i < 8; i++)
1050 {
1051 ImGui::PushID(i);
1052 int frame_padding = -1 + i; // -1 == uses default padding (style.FramePadding)
1053 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible
1054 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left
1055 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);// UV coordinates for (32,32) in our texture
1056 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background
1057 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
1058 if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col))
1059 pressed_count += 1;
1060 ImGui::PopID();
1061 ImGui::SameLine();
1062 }
1063 ImGui::NewLine();
1064 ImGui::Text("Pressed %d times.", pressed_count);
1065 ImGui::TreePop();
1066 }
1067
1068 if (ImGui::TreeNode("Combo"))
1069 {
1070 // Expose flags as checkbox for the demo
1071 static ImGuiComboFlags flags = 0;
1072 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft);
1073 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
1074 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton))
1075 flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both
1076 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview))
1077 flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both
1078
1079 // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
1080 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1081 // stored in the object itself, etc.)
1082 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1083 static int item_current_idx = 0; // Here we store our selection data as an index.
1084 const char* combo_preview_value = items[item_current_idx]; // Pass in the preview value visible before opening the combo (it could be anything)
1085 if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
1086 {
1087 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1088 {
1089 const bool is_selected = (item_current_idx == n);
1090 if (ImGui::Selectable(items[n], is_selected))
1091 item_current_idx = n;
1092
1093 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1094 if (is_selected)
1095 ImGui::SetItemDefaultFocus();
1096 }
1097 ImGui::EndCombo();
1098 }
1099
1100 // Simplified one-liner Combo() API, using values packed in a single constant string
1101 // This is a convenience for when the selection set is small and known at compile-time.
1102 static int item_current_2 = 0;
1103 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1104
1105 // Simplified one-liner Combo() using an array of const char*
1106 // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control.
1107 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
1108 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
1109
1110 // Simplified one-liner Combo() using an accessor function
1111 struct Funcs { static bool ItemGetter(void* data, int n, const char** out_str) { *out_str = ((const char**)data)[n]; return true; } };
1112 static int item_current_4 = 0;
1113 ImGui::Combo("combo 4 (function)", &item_current_4, &Funcs::ItemGetter, items, IM_ARRAYSIZE(items));
1114
1115 ImGui::TreePop();
1116 }
1117
1118 if (ImGui::TreeNode("List boxes"))
1119 {
1120 // Using the generic BeginListBox() API, you have full control over how to display the combo contents.
1121 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
1122 // stored in the object itself, etc.)
1123 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
1124 static int item_current_idx = 0; // Here we store our selection data as an index.
1125 if (ImGui::BeginListBox("listbox 1"))
1126 {
1127 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1128 {
1129 const bool is_selected = (item_current_idx == n);
1130 if (ImGui::Selectable(items[n], is_selected))
1131 item_current_idx = n;
1132
1133 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1134 if (is_selected)
1135 ImGui::SetItemDefaultFocus();
1136 }
1137 ImGui::EndListBox();
1138 }
1139
1140 // Custom size: use all width, 5 items tall
1141 ImGui::Text("Full-width:");
1142 if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
1143 {
1144 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
1145 {
1146 const bool is_selected = (item_current_idx == n);
1147 if (ImGui::Selectable(items[n], is_selected))
1148 item_current_idx = n;
1149
1150 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
1151 if (is_selected)
1152 ImGui::SetItemDefaultFocus();
1153 }
1154 ImGui::EndListBox();
1155 }
1156
1157 ImGui::TreePop();
1158 }
1159
1160 if (ImGui::TreeNode("Selectables"))
1161 {
1162 // Selectable() has 2 overloads:
1163 // - The one taking "bool selected" as a read-only selection information.
1164 // When Selectable() has been clicked it returns true and you can alter selection state accordingly.
1165 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
1166 // The earlier is more flexible, as in real application your selection may be stored in many different ways
1167 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
1168 if (ImGui::TreeNode("Basic"))
1169 {
1170 static bool selection[5] = { false, true, false, false, false };
1171 ImGui::Selectable("1. I am selectable", &selection[0]);
1172 ImGui::Selectable("2. I am selectable", &selection[1]);
1173 ImGui::Text("(I am not selectable)");
1174 ImGui::Selectable("4. I am selectable", &selection[3]);
1175 if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick))
1176 if (ImGui::IsMouseDoubleClicked(0))
1177 selection[4] = !selection[4];
1178 ImGui::TreePop();
1179 }
1180 if (ImGui::TreeNode("Selection State: Single Selection"))
1181 {
1182 static int selected = -1;
1183 for (int n = 0; n < 5; n++)
1184 {
1185 char buf[32];
1186 sprintf(buf, "Object %d", n);
1187 if (ImGui::Selectable(buf, selected == n))
1188 selected = n;
1189 }
1190 ImGui::TreePop();
1191 }
1192 if (ImGui::TreeNode("Selection State: Multiple Selection"))
1193 {
1194 HelpMarker("Hold CTRL and click to select multiple items.");
1195 static bool selection[5] = { false, false, false, false, false };
1196 for (int n = 0; n < 5; n++)
1197 {
1198 char buf[32];
1199 sprintf(buf, "Object %d", n);
1200 if (ImGui::Selectable(buf, selection[n]))
1201 {
1202 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
1203 memset(selection, 0, sizeof(selection));
1204 selection[n] ^= 1;
1205 }
1206 }
1207 ImGui::TreePop();
1208 }
1209 if (ImGui::TreeNode("Rendering more text into the same line"))
1210 {
1211 // Using the Selectable() override that takes "bool* p_selected" parameter,
1212 // this function toggle your bool value automatically.
1213 static bool selected[3] = { false, false, false };
1214 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
1215 ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes");
1216 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
1217 ImGui::TreePop();
1218 }
1219 if (ImGui::TreeNode("In columns"))
1220 {
1221 static bool selected[10] = {};
1222
1223 if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1224 {
1225 for (int i = 0; i < 10; i++)
1226 {
1227 char label[32];
1228 sprintf(label, "Item %d", i);
1229 ImGui::TableNextColumn();
1230 ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap
1231 }
1232 ImGui::EndTable();
1233 }
1234 ImGui::Spacing();
1235 if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
1236 {
1237 for (int i = 0; i < 10; i++)
1238 {
1239 char label[32];
1240 sprintf(label, "Item %d", i);
1241 ImGui::TableNextRow();
1242 ImGui::TableNextColumn();
1243 ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns);
1244 ImGui::TableNextColumn();
1245 ImGui::Text("Some other contents");
1246 ImGui::TableNextColumn();
1247 ImGui::Text("123456");
1248 }
1249 ImGui::EndTable();
1250 }
1251 ImGui::TreePop();
1252 }
1253 if (ImGui::TreeNode("Grid"))
1254 {
1255 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
1256
1257 // Add in a bit of silly fun...
1258 const float time = (float)ImGui::GetTime();
1259 const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
1260 if (winning_state)
1261 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
1262
1263 for (int y = 0; y < 4; y++)
1264 for (int x = 0; x < 4; x++)
1265 {
1266 if (x > 0)
1267 ImGui::SameLine();
1268 ImGui::PushID(y * 4 + x);
1269 if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
1270 {
1271 // Toggle clicked cell + toggle neighbors
1272 selected[y][x] ^= 1;
1273 if (x > 0) { selected[y][x - 1] ^= 1; }
1274 if (x < 3) { selected[y][x + 1] ^= 1; }
1275 if (y > 0) { selected[y - 1][x] ^= 1; }
1276 if (y < 3) { selected[y + 1][x] ^= 1; }
1277 }
1278 ImGui::PopID();
1279 }
1280
1281 if (winning_state)
1282 ImGui::PopStyleVar();
1283 ImGui::TreePop();
1284 }
1285 if (ImGui::TreeNode("Alignment"))
1286 {
1287 HelpMarker(
1288 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
1289 "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
1290 "left-align otherwise it becomes difficult to layout multiple items on a same line");
1291 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
1292 for (int y = 0; y < 3; y++)
1293 {
1294 for (int x = 0; x < 3; x++)
1295 {
1296 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
1297 char name[32];
1298 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
1299 if (x > 0) ImGui::SameLine();
1300 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
1301 ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
1302 ImGui::PopStyleVar();
1303 }
1304 }
1305 ImGui::TreePop();
1306 }
1307 ImGui::TreePop();
1308 }
1309
1310 // To wire InputText() with std::string or any other custom string type,
1311 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
1312 if (ImGui::TreeNode("Text Input"))
1313 {
1314 if (ImGui::TreeNode("Multi-line Text Input"))
1315 {
1316 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
1317 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
1318 static char text[1024 * 16] =
1319 "/*\n"
1320 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
1321 " the hexadecimal encoding of one offending instruction,\n"
1322 " more formally, the invalid operand with locked CMPXCHG8B\n"
1323 " instruction bug, is a design flaw in the majority of\n"
1324 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
1325 " processors (all in the P5 microarchitecture).\n"
1326 "*/\n\n"
1327 "label:\n"
1328 "\tlock cmpxchg8b eax\n";
1329
1330 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
1331 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)");
1332 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
1333 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput);
1334 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
1335 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
1336 ImGui::TreePop();
1337 }
1338
1339 if (ImGui::TreeNode("Filtered Text Input"))
1340 {
1341 struct TextFilters
1342 {
1343 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i'
1344 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
1345 {
1346 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
1347 return 0;
1348 return 1;
1349 }
1350 };
1351
1352 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64);
1353 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal);
1354 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
1355 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase);
1356 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank);
1357 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters);
1358 ImGui::TreePop();
1359 }
1360
1361 if (ImGui::TreeNode("Password Input"))
1362 {
1363 static char password[64] = "password123";
1364 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1365 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
1366 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
1367 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
1368 ImGui::TreePop();
1369 }
1370
1371 if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
1372 {
1373 struct Funcs
1374 {
1375 static int MyCallback(ImGuiInputTextCallbackData* data)
1376 {
1377 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
1378 {
1379 data->InsertChars(data->CursorPos, "..");
1380 }
1381 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
1382 {
1383 if (data->EventKey == ImGuiKey_UpArrow)
1384 {
1385 data->DeleteChars(0, data->BufTextLen);
1386 data->InsertChars(0, "Pressed Up!");
1387 data->SelectAll();
1388 }
1389 else if (data->EventKey == ImGuiKey_DownArrow)
1390 {
1391 data->DeleteChars(0, data->BufTextLen);
1392 data->InsertChars(0, "Pressed Down!");
1393 data->SelectAll();
1394 }
1395 }
1396 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
1397 {
1398 // Toggle casing of first character
1399 char c = data->Buf[0];
1400 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
1401 data->BufDirty = true;
1402
1403 // Increment a counter
1404 int* p_int = (int*)data->UserData;
1405 *p_int = *p_int + 1;
1406 }
1407 return 0;
1408 }
1409 };
1410 static char buf1[64];
1411 ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
1412 ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.");
1413
1414 static char buf2[64];
1415 ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
1416 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.");
1417
1418 static char buf3[64];
1419 static int edit_count = 0;
1420 ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
1421 ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits.");
1422 ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
1423
1424 ImGui::TreePop();
1425 }
1426
1427 if (ImGui::TreeNode("Resize Callback"))
1428 {
1429 // To wire InputText() with std::string or any other custom string type,
1430 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
1431 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
1432 HelpMarker(
1433 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
1434 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
1435 struct Funcs
1436 {
1437 static int MyResizeCallback(ImGuiInputTextCallbackData* data)
1438 {
1439 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
1440 {
1441 ImVector<char>* my_str = (ImVector<char>*)data->UserData;
1442 IM_ASSERT(my_str->begin() == data->Buf);
1443 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
1444 data->Buf = my_str->begin();
1445 }
1446 return 0;
1447 }
1448
1449 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
1450 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
1451 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
1452 {
1453 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
1454 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
1455 }
1456 };
1457
1458 // For this demo we are using ImVector as a string container.
1459 // Note that because we need to store a terminating zero character, our size/capacity are 1 more
1460 // than usually reported by a typical string class.
1461 static ImVector<char> my_str;
1462 if (my_str.empty())
1463 my_str.push_back(0);
1464 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
1465 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
1466 ImGui::TreePop();
1467 }
1468
1469 ImGui::TreePop();
1470 }
1471
1472 // Tabs
1473 if (ImGui::TreeNode("Tabs"))
1474 {
1475 if (ImGui::TreeNode("Basic"))
1476 {
1477 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1478 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1479 {
1480 if (ImGui::BeginTabItem("Avocado"))
1481 {
1482 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
1483 ImGui::EndTabItem();
1484 }
1485 if (ImGui::BeginTabItem("Broccoli"))
1486 {
1487 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
1488 ImGui::EndTabItem();
1489 }
1490 if (ImGui::BeginTabItem("Cucumber"))
1491 {
1492 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
1493 ImGui::EndTabItem();
1494 }
1495 ImGui::EndTabBar();
1496 }
1497 ImGui::Separator();
1498 ImGui::TreePop();
1499 }
1500
1501 if (ImGui::TreeNode("Advanced & Close Button"))
1502 {
1503 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1504 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1505 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable);
1506 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
1507 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1508 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1509 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1510 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1511 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1512 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1513 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1514 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1515
1516 // Tab Bar
1517 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1518 static bool opened[4] = { true, true, true, true }; // Persistent user state
1519 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1520 {
1521 if (n > 0) { ImGui::SameLine(); }
1522 ImGui::Checkbox(names[n], &opened[n]);
1523 }
1524
1525 // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
1526 // the underlying bool will be set to false when the tab is closed.
1527 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1528 {
1529 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1530 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
1531 {
1532 ImGui::Text("This is the %s tab!", names[n]);
1533 if (n & 1)
1534 ImGui::Text("I am an odd tab.");
1535 ImGui::EndTabItem();
1536 }
1537 ImGui::EndTabBar();
1538 }
1539 ImGui::Separator();
1540 ImGui::TreePop();
1541 }
1542
1543 if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
1544 {
1545 static ImVector<int> active_tabs;
1546 static int next_tab_id = 0;
1547 if (next_tab_id == 0) // Initialize with some default tabs
1548 for (int i = 0; i < 3; i++)
1549 active_tabs.push_back(next_tab_id++);
1550
1551 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
1552 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
1553 // but they tend to make more sense together)
1554 static bool show_leading_button = true;
1555 static bool show_trailing_button = true;
1556 ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
1557 ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
1558
1559 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
1560 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
1561 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1562 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1563 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1564 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1565 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1566
1567 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1568 {
1569 // Demo a Leading TabItemButton(): click the "?" button to open a menu
1570 if (show_leading_button)
1571 if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
1572 ImGui::OpenPopup("MyHelpMenu");
1573 if (ImGui::BeginPopup("MyHelpMenu"))
1574 {
1575 ImGui::Selectable("Hello!");
1576 ImGui::EndPopup();
1577 }
1578
1579 // Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+")
1580 // Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
1581 if (show_trailing_button)
1582 if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
1583 active_tabs.push_back(next_tab_id++); // Add new tab
1584
1585 // Submit our regular tabs
1586 for (int n = 0; n < active_tabs.Size; )
1587 {
1588 bool open = true;
1589 char name[16];
1590 snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
1591 if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
1592 {
1593 ImGui::Text("This is the %s tab!", name);
1594 ImGui::EndTabItem();
1595 }
1596
1597 if (!open)
1598 active_tabs.erase(active_tabs.Data + n);
1599 else
1600 n++;
1601 }
1602
1603 ImGui::EndTabBar();
1604 }
1605 ImGui::Separator();
1606 ImGui::TreePop();
1607 }
1608 ImGui::TreePop();
1609 }
1610
1611 // Plot/Graph widgets are not very good.
1612 // Consider writing your own, or using a third-party one, see:
1613 // - ImPlot https://github.com/epezent/implot
1614 // - others https://github.com/ocornut/imgui/wiki/Useful-Extensions
1615 if (ImGui::TreeNode("Plots Widgets"))
1616 {
1617 static bool animate = true;
1618 ImGui::Checkbox("Animate", &animate);
1619
1620 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
1621 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
1622
1623 // Fill an array of contiguous float values to plot
1624 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
1625 // and the sizeof() of your structure in the "stride" parameter.
1626 static float values[90] = {};
1627 static int values_offset = 0;
1628 static double refresh_time = 0.0;
1629 if (!animate || refresh_time == 0.0)
1630 refresh_time = ImGui::GetTime();
1631 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
1632 {
1633 static float phase = 0.0f;
1634 values[values_offset] = cosf(phase);
1635 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
1636 phase += 0.10f * values_offset;
1637 refresh_time += 1.0f / 60.0f;
1638 }
1639
1640 // Plots can display overlay texts
1641 // (in this example, we will display an average value)
1642 {
1643 float average = 0.0f;
1644 for (int n = 0; n < IM_ARRAYSIZE(values); n++)
1645 average += values[n];
1646 average /= (float)IM_ARRAYSIZE(values);
1647 char overlay[32];
1648 sprintf(overlay, "avg %f", average);
1649 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
1650 }
1651 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
1652
1653 // Use functions to generate output
1654 // FIXME: This is rather awkward because current plot API only pass in indices.
1655 // We probably want an API passing floats and user provide sample rate/count.
1656 struct Funcs
1657 {
1658 static float Sin(void*, int i) { return sinf(i * 0.1f); }
1659 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
1660 };
1661 static int func_type = 0, display_count = 70;
1662 ImGui::Separator();
1663 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
1664 ImGui::Combo("func", &func_type, "Sin\0Saw\0");
1665 ImGui::SameLine();
1666 ImGui::SliderInt("Sample count", &display_count, 1, 400);
1667 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
1668 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
1669 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
1670 ImGui::Separator();
1671
1672 // Animate a simple progress bar
1673 static float progress = 0.0f, progress_dir = 1.0f;
1674 if (animate)
1675 {
1676 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
1677 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
1678 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
1679 }
1680
1681 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
1682 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
1683 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
1684 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
1685 ImGui::Text("Progress Bar");
1686
1687 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
1688 char buf[32];
1689 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
1690 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
1691 ImGui::TreePop();
1692 }
1693
1694 if (ImGui::TreeNode("Color/Picker Widgets"))
1695 {
1696 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
1697
1698 static bool alpha_preview = true;
1699 static bool alpha_half_preview = false;
1700 static bool drag_and_drop = true;
1701 static bool options_menu = true;
1702 static bool hdr = false;
1703 ImGui::Checkbox("With Alpha Preview", &alpha_preview);
1704 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
1705 ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
1706 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
1707 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
1708 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);
1709
1710 ImGui::Text("Color widget:");
1711 ImGui::SameLine(); HelpMarker(
1712 "Click on the color square to open a color picker.\n"
1713 "CTRL+click on individual component to input value.\n");
1714 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
1715
1716 ImGui::Text("Color widget HSV with Alpha:");
1717 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
1718
1719 ImGui::Text("Color widget with Float Display:");
1720 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
1721
1722 ImGui::Text("Color button with Picker:");
1723 ImGui::SameLine(); HelpMarker(
1724 "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
1725 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
1726 "be used for the tooltip and picker popup.");
1727 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
1728
1729 ImGui::Text("Color button with Custom Picker Popup:");
1730
1731 // Generate a default palette. The palette will persist and can be edited.
1732 static bool saved_palette_init = true;
1733 static ImVec4 saved_palette[32] = {};
1734 if (saved_palette_init)
1735 {
1736 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
1737 {
1738 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
1739 saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
1740 saved_palette[n].w = 1.0f; // Alpha
1741 }
1742 saved_palette_init = false;
1743 }
1744
1745 static ImVec4 backup_color;
1746 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
1747 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
1748 open_popup |= ImGui::Button("Palette");
1749 if (open_popup)
1750 {
1751 ImGui::OpenPopup("mypicker");
1752 backup_color = color;
1753 }
1754 if (ImGui::BeginPopup("mypicker"))
1755 {
1756 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
1757 ImGui::Separator();
1758 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
1759 ImGui::SameLine();
1760
1761 ImGui::BeginGroup(); // Lock X position
1762 ImGui::Text("Current");
1763 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
1764 ImGui::Text("Previous");
1765 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
1766 color = backup_color;
1767 ImGui::Separator();
1768 ImGui::Text("Palette");
1769 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
1770 {
1771 ImGui::PushID(n);
1772 if ((n % 8) != 0)
1773 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
1774
1775 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
1776 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
1777 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
1778
1779 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
1780 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
1781 if (ImGui::BeginDragDropTarget())
1782 {
1783 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
1784 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
1785 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
1786 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
1787 ImGui::EndDragDropTarget();
1788 }
1789
1790 ImGui::PopID();
1791 }
1792 ImGui::EndGroup();
1793 ImGui::EndPopup();
1794 }
1795
1796 ImGui::Text("Color button only:");
1797 static bool no_border = false;
1798 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
1799 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
1800
1801 ImGui::Text("Color picker:");
1802 static bool alpha = true;
1803 static bool alpha_bar = true;
1804 static bool side_preview = true;
1805 static bool ref_color = false;
1806 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
1807 static int display_mode = 0;
1808 static int picker_mode = 0;
1809 ImGui::Checkbox("With Alpha", &alpha);
1810 ImGui::Checkbox("With Alpha Bar", &alpha_bar);
1811 ImGui::Checkbox("With Side Preview", &side_preview);
1812 if (side_preview)
1813 {
1814 ImGui::SameLine();
1815 ImGui::Checkbox("With Ref Color", &ref_color);
1816 if (ref_color)
1817 {
1818 ImGui::SameLine();
1819 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
1820 }
1821 }
1822 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
1823 ImGui::SameLine(); HelpMarker(
1824 "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
1825 "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
1826 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
1827 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
1828 ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode.");
1829 ImGuiColorEditFlags flags = misc_flags;
1830 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
1831 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
1832 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
1833 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
1834 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
1835 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays
1836 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode
1837 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
1838 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
1839 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
1840
1841 ImGui::Text("Set defaults in code:");
1842 ImGui::SameLine(); HelpMarker(
1843 "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
1844 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
1845 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
1846 "encouraging you to persistently save values that aren't forward-compatible.");
1847 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
1848 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
1849 if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
1850 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
1851
1852 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
1853 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
1854 ImGui::Spacing();
1855 ImGui::Text("HSV encoded colors");
1856 ImGui::SameLine(); HelpMarker(
1857 "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
1858 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
1859 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
1860 ImGui::Text("Color widget with InputHSV:");
1861 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1862 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
1863 ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
1864
1865 ImGui::TreePop();
1866 }
1867
1868 if (ImGui::TreeNode("Drag/Slider Flags"))
1869 {
1870 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
1871 static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
1872 ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
1873 ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
1874 ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
1875 ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
1876 ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
1877 ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
1878 ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
1879 ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
1880
1881 // Drags
1882 static float drag_f = 0.5f;
1883 static int drag_i = 50;
1884 ImGui::Text("Underlying float value: %f", drag_f);
1885 ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
1886 ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
1887 ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
1888 ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
1889 ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
1890
1891 // Sliders
1892 static float slider_f = 0.5f;
1893 static int slider_i = 50;
1894 ImGui::Text("Underlying float value: %f", slider_f);
1895 ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
1896 ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
1897
1898 ImGui::TreePop();
1899 }
1900
1901 if (ImGui::TreeNode("Range Widgets"))
1902 {
1903 static float begin = 10, end = 90;
1904 static int begin_i = 100, end_i = 1000;
1905 ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
1906 ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
1907 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
1908 ImGui::TreePop();
1909 }
1910
1911 if (ImGui::TreeNode("Data Types"))
1912 {
1913 // DragScalar/InputScalar/SliderScalar functions allow various data types
1914 // - signed/unsigned
1915 // - 8/16/32/64-bits
1916 // - integer/float/double
1917 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
1918 // to pass the type, and passing all arguments by pointer.
1919 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types.
1920 // In practice, if you frequently use a given type that is not covered by the normal API entry points,
1921 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
1922 // and then pass their address to the generic function. For example:
1923 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
1924 // {
1925 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
1926 // }
1927
1928 // Setup limits (as helper variables so we can take their address, as explained above)
1929 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
1930 #ifndef LLONG_MIN
1931 ImS64 LLONG_MIN = -9223372036854775807LL - 1;
1932 ImS64 LLONG_MAX = 9223372036854775807LL;
1933 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
1934 #endif
1935 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127;
1936 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255;
1937 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767;
1938 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535;
1939 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;
1940 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;
1941 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;
1942 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;
1943 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
1944 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
1945
1946 // State
1947 static char s8_v = 127;
1948 static ImU8 u8_v = 255;
1949 static short s16_v = 32767;
1950 static ImU16 u16_v = 65535;
1951 static ImS32 s32_v = -1;
1952 static ImU32 u32_v = (ImU32)-1;
1953 static ImS64 s64_v = -1;
1954 static ImU64 u64_v = (ImU64)-1;
1955 static float f32_v = 0.123f;
1956 static double f64_v = 90000.01234567890123456789;
1957
1958 const float drag_speed = 0.2f;
1959 static bool drag_clamp = false;
1960 ImGui::Text("Drags:");
1961 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
1962 ImGui::SameLine(); HelpMarker(
1963 "As with every widgets in dear imgui, we never modify values unless there is a user interaction.\n"
1964 "You can override the clamping limits by using CTRL+Click to input a value.");
1965 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL);
1966 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms");
1967 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
1968 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
1969 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
1970 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
1971 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
1972 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
1973 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f");
1974 ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
1975 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams");
1976 ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
1977
1978 ImGui::Text("Sliders");
1979 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d");
1980 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u");
1981 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d");
1982 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u");
1983 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
1984 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
1985 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
1986 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
1987 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
1988 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
1989 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" IM_PRId64);
1990 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" IM_PRId64);
1991 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" IM_PRId64);
1992 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" IM_PRIu64 " ms");
1993 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" IM_PRIu64 " ms");
1994 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" IM_PRIu64 " ms");
1995 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
1996 ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
1997 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
1998 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams");
1999 ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic);
2000 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
2001
2002 ImGui::Text("Sliders (reverse)");
2003 ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d");
2004 ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
2005 ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
2006 ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
2007 ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" IM_PRId64);
2008 ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" IM_PRIu64 " ms");
2009
2010 static bool inputs_step = true;
2011 ImGui::Text("Inputs");
2012 ImGui::Checkbox("Show step buttons", &inputs_step);
2013 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d");
2014 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u");
2015 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d");
2016 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u");
2017 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
2018 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
2019 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
2020 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
2021 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL);
2022 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL);
2023 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL);
2024 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL);
2025
2026 ImGui::TreePop();
2027 }
2028
2029 if (ImGui::TreeNode("Multi-component Widgets"))
2030 {
2031 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
2032 static int vec4i[4] = { 1, 5, 100, 255 };
2033
2034 ImGui::InputFloat2("input float2", vec4f);
2035 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
2036 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
2037 ImGui::InputInt2("input int2", vec4i);
2038 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
2039 ImGui::SliderInt2("slider int2", vec4i, 0, 255);
2040 ImGui::Spacing();
2041
2042 ImGui::InputFloat3("input float3", vec4f);
2043 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
2044 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
2045 ImGui::InputInt3("input int3", vec4i);
2046 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
2047 ImGui::SliderInt3("slider int3", vec4i, 0, 255);
2048 ImGui::Spacing();
2049
2050 ImGui::InputFloat4("input float4", vec4f);
2051 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
2052 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
2053 ImGui::InputInt4("input int4", vec4i);
2054 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
2055 ImGui::SliderInt4("slider int4", vec4i, 0, 255);
2056
2057 ImGui::TreePop();
2058 }
2059
2060 if (ImGui::TreeNode("Vertical Sliders"))
2061 {
2062 const float spacing = 4;
2063 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
2064
2065 static int int_value = 0;
2066 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
2067 ImGui::SameLine();
2068
2069 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
2070 ImGui::PushID("set1");
2071 for (int i = 0; i < 7; i++)
2072 {
2073 if (i > 0) ImGui::SameLine();
2074 ImGui::PushID(i);
2075 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
2076 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
2077 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
2078 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
2079 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
2080 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2081 ImGui::SetTooltip("%.3f", values[i]);
2082 ImGui::PopStyleColor(4);
2083 ImGui::PopID();
2084 }
2085 ImGui::PopID();
2086
2087 ImGui::SameLine();
2088 ImGui::PushID("set2");
2089 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
2090 const int rows = 3;
2091 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
2092 for (int nx = 0; nx < 4; nx++)
2093 {
2094 if (nx > 0) ImGui::SameLine();
2095 ImGui::BeginGroup();
2096 for (int ny = 0; ny < rows; ny++)
2097 {
2098 ImGui::PushID(nx * rows + ny);
2099 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
2100 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
2101 ImGui::SetTooltip("%.3f", values2[nx]);
2102 ImGui::PopID();
2103 }
2104 ImGui::EndGroup();
2105 }
2106 ImGui::PopID();
2107
2108 ImGui::SameLine();
2109 ImGui::PushID("set3");
2110 for (int i = 0; i < 4; i++)
2111 {
2112 if (i > 0) ImGui::SameLine();
2113 ImGui::PushID(i);
2114 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
2115 ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
2116 ImGui::PopStyleVar();
2117 ImGui::PopID();
2118 }
2119 ImGui::PopID();
2120 ImGui::PopStyleVar();
2121 ImGui::TreePop();
2122 }
2123
2124 if (ImGui::TreeNode("Drag and Drop"))
2125 {
2126 if (ImGui::TreeNode("Drag and drop in standard widgets"))
2127 {
2128 // ColorEdit widgets automatically act as drag source and drag target.
2129 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
2130 // to allow your own widgets to use colors in their drag and drop interaction.
2131 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
2132 HelpMarker("You can drag from the color squares.");
2133 static float col1[3] = { 1.0f, 0.0f, 0.2f };
2134 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
2135 ImGui::ColorEdit3("color 1", col1);
2136 ImGui::ColorEdit4("color 2", col2);
2137 ImGui::TreePop();
2138 }
2139
2140 if (ImGui::TreeNode("Drag and drop to copy/swap items"))
2141 {
2142 enum Mode
2143 {
2144 Mode_Copy,
2145 Mode_Move,
2146 Mode_Swap
2147 };
2148 static int mode = 0;
2149 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
2150 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
2151 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
2152 static const char* names[9] =
2153 {
2154 "Bobby", "Beatrice", "Betty",
2155 "Brianna", "Barry", "Bernard",
2156 "Bibi", "Blaine", "Bryn"
2157 };
2158 for (int n = 0; n < IM_ARRAYSIZE(names); n++)
2159 {
2160 ImGui::PushID(n);
2161 if ((n % 3) != 0)
2162 ImGui::SameLine();
2163 ImGui::Button(names[n], ImVec2(60, 60));
2164
2165 // Our buttons are both drag sources and drag targets here!
2166 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
2167 {
2168 // Set payload to carry the index of our item (could be anything)
2169 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
2170
2171 // Display preview (could be anything, e.g. when dragging an image we could decide to display
2172 // the filename and a small preview of the image, etc.)
2173 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
2174 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
2175 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
2176 ImGui::EndDragDropSource();
2177 }
2178 if (ImGui::BeginDragDropTarget())
2179 {
2180 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
2181 {
2182 IM_ASSERT(payload->DataSize == sizeof(int));
2183 int payload_n = *(const int*)payload->Data;
2184 if (mode == Mode_Copy)
2185 {
2186 names[n] = names[payload_n];
2187 }
2188 if (mode == Mode_Move)
2189 {
2190 names[n] = names[payload_n];
2191 names[payload_n] = "";
2192 }
2193 if (mode == Mode_Swap)
2194 {
2195 const char* tmp = names[n];
2196 names[n] = names[payload_n];
2197 names[payload_n] = tmp;
2198 }
2199 }
2200 ImGui::EndDragDropTarget();
2201 }
2202 ImGui::PopID();
2203 }
2204 ImGui::TreePop();
2205 }
2206
2207 if (ImGui::TreeNode("Drag to reorder items (simple)"))
2208 {
2209 // Simple reordering
2210 HelpMarker(
2211 "We don't use the drag and drop api at all here! "
2212 "Instead we query when the item is held but not hovered, and order items accordingly.");
2213 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
2214 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
2215 {
2216 const char* item = item_names[n];
2217 ImGui::Selectable(item);
2218
2219 if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
2220 {
2221 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
2222 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
2223 {
2224 item_names[n] = item_names[n_next];
2225 item_names[n_next] = item;
2226 ImGui::ResetMouseDragDelta();
2227 }
2228 }
2229 }
2230 ImGui::TreePop();
2231 }
2232
2233 ImGui::TreePop();
2234 }
2235
2236 if (ImGui::TreeNode("Querying Status (Edited/Active/Focused/Hovered etc.)"))
2237 {
2238 // Select an item type
2239 const char* item_names[] =
2240 {
2241 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat",
2242 "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
2243 };
2244 static int item_type = 1;
2245 ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
2246 ImGui::SameLine();
2247 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().");
2248
2249 // Submit selected item item so we can query their status in the code following it.
2250 bool ret = false;
2251 static bool b = false;
2252 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
2253 static char str[16] = {};
2254 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
2255 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
2256 if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
2257 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
2258 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
2259 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
2260 if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
2261 if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2262 if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
2263 if (item_type == 9) { ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item
2264 if (item_type == 10){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
2265 if (item_type == 11){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
2266 if (item_type == 12){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
2267 if (item_type == 13){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); }
2268 if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
2269
2270 // Display the values of IsItemHovered() and other common item state functions.
2271 // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2272 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
2273 // we query every state in a single call to avoid storing them and to simplify the code.
2274 ImGui::BulletText(
2275 "Return value = %d\n"
2276 "IsItemFocused() = %d\n"
2277 "IsItemHovered() = %d\n"
2278 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2279 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2280 "IsItemHovered(_AllowWhenOverlapped) = %d\n"
2281 "IsItemHovered(_RectOnly) = %d\n"
2282 "IsItemActive() = %d\n"
2283 "IsItemEdited() = %d\n"
2284 "IsItemActivated() = %d\n"
2285 "IsItemDeactivated() = %d\n"
2286 "IsItemDeactivatedAfterEdit() = %d\n"
2287 "IsItemVisible() = %d\n"
2288 "IsItemClicked() = %d\n"
2289 "IsItemToggledOpen() = %d\n"
2290 "GetItemRectMin() = (%.1f, %.1f)\n"
2291 "GetItemRectMax() = (%.1f, %.1f)\n"
2292 "GetItemRectSize() = (%.1f, %.1f)",
2293 ret,
2294 ImGui::IsItemFocused(),
2295 ImGui::IsItemHovered(),
2296 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2297 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2298 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped),
2299 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
2300 ImGui::IsItemActive(),
2301 ImGui::IsItemEdited(),
2302 ImGui::IsItemActivated(),
2303 ImGui::IsItemDeactivated(),
2304 ImGui::IsItemDeactivatedAfterEdit(),
2305 ImGui::IsItemVisible(),
2306 ImGui::IsItemClicked(),
2307 ImGui::IsItemToggledOpen(),
2308 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
2309 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
2310 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
2311 );
2312
2313 static bool embed_all_inside_a_child_window = false;
2314 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window);
2315 if (embed_all_inside_a_child_window)
2316 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true);
2317
2318 // Testing IsWindowFocused() function with its various flags.
2319 // Note that the ImGuiFocusedFlags_XXX flags can be combined.
2320 ImGui::BulletText(
2321 "IsWindowFocused() = %d\n"
2322 "IsWindowFocused(_ChildWindows) = %d\n"
2323 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2324 "IsWindowFocused(_RootWindow) = %d\n"
2325 "IsWindowFocused(_AnyWindow) = %d\n",
2326 ImGui::IsWindowFocused(),
2327 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2328 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2329 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2330 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2331
2332 // Testing IsWindowHovered() function with its various flags.
2333 // Note that the ImGuiHoveredFlags_XXX flags can be combined.
2334 ImGui::BulletText(
2335 "IsWindowHovered() = %d\n"
2336 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2337 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2338 "IsWindowHovered(_ChildWindows) = %d\n"
2339 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2340 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
2341 "IsWindowHovered(_RootWindow) = %d\n"
2342 "IsWindowHovered(_AnyWindow) = %d\n",
2343 ImGui::IsWindowHovered(),
2344 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2345 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2346 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2347 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2348 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2349 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2350 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));
2351
2352 ImGui::BeginChild("child", ImVec2(0, 50), true);
2353 ImGui::Text("This is another child window for testing the _ChildWindows flag.");
2354 ImGui::EndChild();
2355 if (embed_all_inside_a_child_window)
2356 ImGui::EndChild();
2357
2358 static char unused_str[] = "This widget is only here to be able to tab-out of the widgets above.";
2359 ImGui::InputText("unused", unused_str, IM_ARRAYSIZE(unused_str), ImGuiInputTextFlags_ReadOnly);
2360
2361 // Calling IsItemHovered() after begin returns the hovered status of the title bar.
2362 // This is useful in particular if you want to create a context menu associated to the title bar of a window.
2363 // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
2364 static bool test_window = false;
2365 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
2366 if (test_window)
2367 {
2368 // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck.
2369 // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"?
2370 ImGui::Begin("Title bar Hovered/Active tests", &test_window);
2371 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
2372 {
2373 if (ImGui::MenuItem("Close")) { test_window = false; }
2374 ImGui::EndPopup();
2375 }
2376 ImGui::Text(
2377 "IsItemHovered() after begin = %d (== is title bar hovered)\n"
2378 "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
2379 ImGui::IsItemHovered(), ImGui::IsItemActive());
2380 ImGui::End();
2381 }
2382
2383 ImGui::TreePop();
2384 }
2385 }
2386
ShowDemoWindowLayout()2387 static void ShowDemoWindowLayout()
2388 {
2389 if (!ImGui::CollapsingHeader("Layout & Scrolling"))
2390 return;
2391
2392 if (ImGui::TreeNode("Child windows"))
2393 {
2394 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
2395 static bool disable_mouse_wheel = false;
2396 static bool disable_menu = false;
2397 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
2398 ImGui::Checkbox("Disable Menu", &disable_menu);
2399
2400 // Child 1: no border, enable horizontal scrollbar
2401 {
2402 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
2403 if (disable_mouse_wheel)
2404 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2405 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags);
2406 for (int i = 0; i < 100; i++)
2407 ImGui::Text("%04d: scrollable region", i);
2408 ImGui::EndChild();
2409 }
2410
2411 ImGui::SameLine();
2412
2413 // Child 2: rounded border
2414 {
2415 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
2416 if (disable_mouse_wheel)
2417 window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
2418 if (!disable_menu)
2419 window_flags |= ImGuiWindowFlags_MenuBar;
2420 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
2421 ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags);
2422 if (!disable_menu && ImGui::BeginMenuBar())
2423 {
2424 if (ImGui::BeginMenu("Menu"))
2425 {
2426 ShowExampleMenuFile();
2427 ImGui::EndMenu();
2428 }
2429 ImGui::EndMenuBar();
2430 }
2431 if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings))
2432 {
2433 for (int i = 0; i < 100; i++)
2434 {
2435 char buf[32];
2436 sprintf(buf, "%03d", i);
2437 ImGui::TableNextColumn();
2438 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
2439 }
2440 ImGui::EndTable();
2441 }
2442 ImGui::EndChild();
2443 ImGui::PopStyleVar();
2444 }
2445
2446 ImGui::Separator();
2447
2448 // Demonstrate a few extra things
2449 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
2450 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
2451 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively
2452 // layout from this position.
2453 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
2454 // the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details.
2455 {
2456 static int offset_x = 0;
2457 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
2458 ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
2459
2460 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
2461 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
2462 ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None);
2463 for (int n = 0; n < 50; n++)
2464 ImGui::Text("Some test %d", n);
2465 ImGui::EndChild();
2466 bool child_is_hovered = ImGui::IsItemHovered();
2467 ImVec2 child_rect_min = ImGui::GetItemRectMin();
2468 ImVec2 child_rect_max = ImGui::GetItemRectMax();
2469 ImGui::PopStyleColor();
2470 ImGui::Text("Hovered: %d", child_is_hovered);
2471 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);
2472 }
2473
2474 ImGui::TreePop();
2475 }
2476
2477 if (ImGui::TreeNode("Widgets Width"))
2478 {
2479 static float f = 0.0f;
2480 static bool show_indented_items = true;
2481 ImGui::Checkbox("Show indented items", &show_indented_items);
2482
2483 // Use SetNextItemWidth() to set the width of a single upcoming item.
2484 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
2485 // In real code use you'll probably want to choose width values that are proportional to your font size
2486 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
2487
2488 ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
2489 ImGui::SameLine(); HelpMarker("Fixed width.");
2490 ImGui::PushItemWidth(100);
2491 ImGui::DragFloat("float##1b", &f);
2492 if (show_indented_items)
2493 {
2494 ImGui::Indent();
2495 ImGui::DragFloat("float (indented)##1b", &f);
2496 ImGui::Unindent();
2497 }
2498 ImGui::PopItemWidth();
2499
2500 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
2501 ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
2502 ImGui::PushItemWidth(-100);
2503 ImGui::DragFloat("float##2a", &f);
2504 if (show_indented_items)
2505 {
2506 ImGui::Indent();
2507 ImGui::DragFloat("float (indented)##2b", &f);
2508 ImGui::Unindent();
2509 }
2510 ImGui::PopItemWidth();
2511
2512 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
2513 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
2514 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
2515 ImGui::DragFloat("float##3a", &f);
2516 if (show_indented_items)
2517 {
2518 ImGui::Indent();
2519 ImGui::DragFloat("float (indented)##3b", &f);
2520 ImGui::Unindent();
2521 }
2522 ImGui::PopItemWidth();
2523
2524 ImGui::Text("SetNextItemWidth/PushItemWidth(-GetContentRegionAvail().x * 0.5f)");
2525 ImGui::SameLine(); HelpMarker("Align to right edge minus half");
2526 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
2527 ImGui::DragFloat("float##4a", &f);
2528 if (show_indented_items)
2529 {
2530 ImGui::Indent();
2531 ImGui::DragFloat("float (indented)##4b", &f);
2532 ImGui::Unindent();
2533 }
2534 ImGui::PopItemWidth();
2535
2536 // Demonstrate using PushItemWidth to surround three items.
2537 // Calling SetNextItemWidth() before each of them would have the same effect.
2538 ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)");
2539 ImGui::SameLine(); HelpMarker("Align to right edge");
2540 ImGui::PushItemWidth(-FLT_MIN);
2541 ImGui::DragFloat("##float5a", &f);
2542 if (show_indented_items)
2543 {
2544 ImGui::Indent();
2545 ImGui::DragFloat("float (indented)##5b", &f);
2546 ImGui::Unindent();
2547 }
2548 ImGui::PopItemWidth();
2549
2550 ImGui::TreePop();
2551 }
2552
2553 if (ImGui::TreeNode("Basic Horizontal Layout"))
2554 {
2555 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
2556
2557 // Text
2558 ImGui::Text("Two items: Hello"); ImGui::SameLine();
2559 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
2560
2561 // Adjust spacing
2562 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
2563 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
2564
2565 // Button
2566 ImGui::AlignTextToFramePadding();
2567 ImGui::Text("Normal buttons"); ImGui::SameLine();
2568 ImGui::Button("Banana"); ImGui::SameLine();
2569 ImGui::Button("Apple"); ImGui::SameLine();
2570 ImGui::Button("Corniflower");
2571
2572 // Button
2573 ImGui::Text("Small buttons"); ImGui::SameLine();
2574 ImGui::SmallButton("Like this one"); ImGui::SameLine();
2575 ImGui::Text("can fit within a text block.");
2576
2577 // Aligned to arbitrary position. Easy/cheap column.
2578 ImGui::Text("Aligned");
2579 ImGui::SameLine(150); ImGui::Text("x=150");
2580 ImGui::SameLine(300); ImGui::Text("x=300");
2581 ImGui::Text("Aligned");
2582 ImGui::SameLine(150); ImGui::SmallButton("x=150");
2583 ImGui::SameLine(300); ImGui::SmallButton("x=300");
2584
2585 // Checkbox
2586 static bool c1 = false, c2 = false, c3 = false, c4 = false;
2587 ImGui::Checkbox("My", &c1); ImGui::SameLine();
2588 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
2589 ImGui::Checkbox("Is", &c3); ImGui::SameLine();
2590 ImGui::Checkbox("Rich", &c4);
2591
2592 // Various
2593 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
2594 ImGui::PushItemWidth(80);
2595 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
2596 static int item = -1;
2597 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
2598 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
2599 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
2600 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
2601 ImGui::PopItemWidth();
2602
2603 ImGui::PushItemWidth(80);
2604 ImGui::Text("Lists:");
2605 static int selection[4] = { 0, 1, 2, 3 };
2606 for (int i = 0; i < 4; i++)
2607 {
2608 if (i > 0) ImGui::SameLine();
2609 ImGui::PushID(i);
2610 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
2611 ImGui::PopID();
2612 //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i);
2613 }
2614 ImGui::PopItemWidth();
2615
2616 // Dummy
2617 ImVec2 button_sz(40, 40);
2618 ImGui::Button("A", button_sz); ImGui::SameLine();
2619 ImGui::Dummy(button_sz); ImGui::SameLine();
2620 ImGui::Button("B", button_sz);
2621
2622 // Manually wrapping
2623 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
2624 ImGui::Text("Manually wrapping:");
2625 ImGuiStyle& style = ImGui::GetStyle();
2626 int buttons_count = 20;
2627 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
2628 for (int n = 0; n < buttons_count; n++)
2629 {
2630 ImGui::PushID(n);
2631 ImGui::Button("Box", button_sz);
2632 float last_button_x2 = ImGui::GetItemRectMax().x;
2633 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
2634 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
2635 ImGui::SameLine();
2636 ImGui::PopID();
2637 }
2638
2639 ImGui::TreePop();
2640 }
2641
2642 if (ImGui::TreeNode("Groups"))
2643 {
2644 HelpMarker(
2645 "BeginGroup() basically locks the horizontal position for new line. "
2646 "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
2647 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
2648 ImGui::BeginGroup();
2649 {
2650 ImGui::BeginGroup();
2651 ImGui::Button("AAA");
2652 ImGui::SameLine();
2653 ImGui::Button("BBB");
2654 ImGui::SameLine();
2655 ImGui::BeginGroup();
2656 ImGui::Button("CCC");
2657 ImGui::Button("DDD");
2658 ImGui::EndGroup();
2659 ImGui::SameLine();
2660 ImGui::Button("EEE");
2661 ImGui::EndGroup();
2662 if (ImGui::IsItemHovered())
2663 ImGui::SetTooltip("First group hovered");
2664 }
2665 // Capture the group size and create widgets using the same size
2666 ImVec2 size = ImGui::GetItemRectSize();
2667 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
2668 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
2669
2670 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
2671 ImGui::SameLine();
2672 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
2673 ImGui::EndGroup();
2674 ImGui::SameLine();
2675
2676 ImGui::Button("LEVERAGE\nBUZZWORD", size);
2677 ImGui::SameLine();
2678
2679 if (ImGui::BeginListBox("List", size))
2680 {
2681 ImGui::Selectable("Selected", true);
2682 ImGui::Selectable("Not Selected", false);
2683 ImGui::EndListBox();
2684 }
2685
2686 ImGui::TreePop();
2687 }
2688
2689 if (ImGui::TreeNode("Text Baseline Alignment"))
2690 {
2691 {
2692 ImGui::BulletText("Text baseline:");
2693 ImGui::SameLine(); HelpMarker(
2694 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
2695 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
2696 ImGui::Indent();
2697
2698 ImGui::Text("KO Blahblah"); ImGui::SameLine();
2699 ImGui::Button("Some framed item"); ImGui::SameLine();
2700 HelpMarker("Baseline of button will look misaligned with text..");
2701
2702 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
2703 // (because we don't know what's coming after the Text() statement, we need to move the text baseline
2704 // down by FramePadding.y ahead of time)
2705 ImGui::AlignTextToFramePadding();
2706 ImGui::Text("OK Blahblah"); ImGui::SameLine();
2707 ImGui::Button("Some framed item"); ImGui::SameLine();
2708 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
2709
2710 // SmallButton() uses the same vertical padding as Text
2711 ImGui::Button("TEST##1"); ImGui::SameLine();
2712 ImGui::Text("TEST"); ImGui::SameLine();
2713 ImGui::SmallButton("TEST##2");
2714
2715 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
2716 ImGui::AlignTextToFramePadding();
2717 ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
2718 ImGui::Button("Item##1"); ImGui::SameLine();
2719 ImGui::Text("Item"); ImGui::SameLine();
2720 ImGui::SmallButton("Item##2"); ImGui::SameLine();
2721 ImGui::Button("Item##3");
2722
2723 ImGui::Unindent();
2724 }
2725
2726 ImGui::Spacing();
2727
2728 {
2729 ImGui::BulletText("Multi-line text:");
2730 ImGui::Indent();
2731 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
2732 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2733 ImGui::Text("Banana");
2734
2735 ImGui::Text("Banana"); ImGui::SameLine();
2736 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2737 ImGui::Text("One\nTwo\nThree");
2738
2739 ImGui::Button("HOP##1"); ImGui::SameLine();
2740 ImGui::Text("Banana"); ImGui::SameLine();
2741 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2742 ImGui::Text("Banana");
2743
2744 ImGui::Button("HOP##2"); ImGui::SameLine();
2745 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
2746 ImGui::Text("Banana");
2747 ImGui::Unindent();
2748 }
2749
2750 ImGui::Spacing();
2751
2752 {
2753 ImGui::BulletText("Misc items:");
2754 ImGui::Indent();
2755
2756 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
2757 ImGui::Button("80x80", ImVec2(80, 80));
2758 ImGui::SameLine();
2759 ImGui::Button("50x50", ImVec2(50, 50));
2760 ImGui::SameLine();
2761 ImGui::Button("Button()");
2762 ImGui::SameLine();
2763 ImGui::SmallButton("SmallButton()");
2764
2765 // Tree
2766 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
2767 ImGui::Button("Button##1");
2768 ImGui::SameLine(0.0f, spacing);
2769 if (ImGui::TreeNode("Node##1"))
2770 {
2771 // Placeholder tree data
2772 for (int i = 0; i < 6; i++)
2773 ImGui::BulletText("Item %d..", i);
2774 ImGui::TreePop();
2775 }
2776
2777 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
2778 // Otherwise you can use SmallButton() (smaller fit).
2779 ImGui::AlignTextToFramePadding();
2780
2781 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
2782 // other contents below the node.
2783 bool node_open = ImGui::TreeNode("Node##2");
2784 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
2785 if (node_open)
2786 {
2787 // Placeholder tree data
2788 for (int i = 0; i < 6; i++)
2789 ImGui::BulletText("Item %d..", i);
2790 ImGui::TreePop();
2791 }
2792
2793 // Bullet
2794 ImGui::Button("Button##3");
2795 ImGui::SameLine(0.0f, spacing);
2796 ImGui::BulletText("Bullet text");
2797
2798 ImGui::AlignTextToFramePadding();
2799 ImGui::BulletText("Node");
2800 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
2801 ImGui::Unindent();
2802 }
2803
2804 ImGui::TreePop();
2805 }
2806
2807 if (ImGui::TreeNode("Scrolling"))
2808 {
2809 // Vertical scroll functions
2810 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
2811
2812 static int track_item = 50;
2813 static bool enable_track = true;
2814 static bool enable_extra_decorations = false;
2815 static float scroll_to_off_px = 0.0f;
2816 static float scroll_to_pos_px = 200.0f;
2817
2818 ImGui::Checkbox("Decoration", &enable_extra_decorations);
2819
2820 ImGui::Checkbox("Track", &enable_track);
2821 ImGui::PushItemWidth(100);
2822 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
2823
2824 bool scroll_to_off = ImGui::Button("Scroll Offset");
2825 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
2826
2827 bool scroll_to_pos = ImGui::Button("Scroll To Pos");
2828 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
2829 ImGui::PopItemWidth();
2830
2831 if (scroll_to_off || scroll_to_pos)
2832 enable_track = false;
2833
2834 ImGuiStyle& style = ImGui::GetStyle();
2835 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
2836 if (child_w < 1.0f)
2837 child_w = 1.0f;
2838 ImGui::PushID("##VerticalScrolling");
2839 for (int i = 0; i < 5; i++)
2840 {
2841 if (i > 0) ImGui::SameLine();
2842 ImGui::BeginGroup();
2843 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
2844 ImGui::TextUnformatted(names[i]);
2845
2846 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
2847 const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
2848 const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags);
2849 if (ImGui::BeginMenuBar())
2850 {
2851 ImGui::TextUnformatted("abc");
2852 ImGui::EndMenuBar();
2853 }
2854 if (scroll_to_off)
2855 ImGui::SetScrollY(scroll_to_off_px);
2856 if (scroll_to_pos)
2857 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
2858 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
2859 {
2860 for (int item = 0; item < 100; item++)
2861 {
2862 if (enable_track && item == track_item)
2863 {
2864 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
2865 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
2866 }
2867 else
2868 {
2869 ImGui::Text("Item %d", item);
2870 }
2871 }
2872 }
2873 float scroll_y = ImGui::GetScrollY();
2874 float scroll_max_y = ImGui::GetScrollMaxY();
2875 ImGui::EndChild();
2876 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
2877 ImGui::EndGroup();
2878 }
2879 ImGui::PopID();
2880
2881 // Horizontal scroll functions
2882 ImGui::Spacing();
2883 HelpMarker(
2884 "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
2885 "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
2886 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
2887 "equivalent SetScrollFromPosY(+1) wouldn't.");
2888 ImGui::PushID("##HorizontalScrolling");
2889 for (int i = 0; i < 5; i++)
2890 {
2891 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
2892 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
2893 ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
2894 bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags);
2895 if (scroll_to_off)
2896 ImGui::SetScrollX(scroll_to_off_px);
2897 if (scroll_to_pos)
2898 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
2899 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
2900 {
2901 for (int item = 0; item < 100; item++)
2902 {
2903 if (item > 0)
2904 ImGui::SameLine();
2905 if (enable_track && item == track_item)
2906 {
2907 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
2908 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
2909 }
2910 else
2911 {
2912 ImGui::Text("Item %d", item);
2913 }
2914 }
2915 }
2916 float scroll_x = ImGui::GetScrollX();
2917 float scroll_max_x = ImGui::GetScrollMaxX();
2918 ImGui::EndChild();
2919 ImGui::SameLine();
2920 const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
2921 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
2922 ImGui::Spacing();
2923 }
2924 ImGui::PopID();
2925
2926 // Miscellaneous Horizontal Scrolling Demo
2927 HelpMarker(
2928 "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
2929 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
2930 static int lines = 7;
2931 ImGui::SliderInt("Lines", &lines, 1, 15);
2932 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
2933 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
2934 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
2935 ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar);
2936 for (int line = 0; line < lines; line++)
2937 {
2938 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
2939 // If you want to create your own time line for a real application you may be better off manipulating
2940 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
2941 // yourself. You may also want to use the lower-level ImDrawList API.
2942 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
2943 for (int n = 0; n < num_buttons; n++)
2944 {
2945 if (n > 0) ImGui::SameLine();
2946 ImGui::PushID(n + line * 1000);
2947 char num_buf[16];
2948 sprintf(num_buf, "%d", n);
2949 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
2950 float hue = n * 0.05f;
2951 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
2952 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
2953 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
2954 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
2955 ImGui::PopStyleColor(3);
2956 ImGui::PopID();
2957 }
2958 }
2959 float scroll_x = ImGui::GetScrollX();
2960 float scroll_max_x = ImGui::GetScrollMaxX();
2961 ImGui::EndChild();
2962 ImGui::PopStyleVar(2);
2963 float scroll_x_delta = 0.0f;
2964 ImGui::SmallButton("<<");
2965 if (ImGui::IsItemActive())
2966 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
2967 ImGui::SameLine();
2968 ImGui::Text("Scroll from code"); ImGui::SameLine();
2969 ImGui::SmallButton(">>");
2970 if (ImGui::IsItemActive())
2971 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
2972 ImGui::SameLine();
2973 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
2974 if (scroll_x_delta != 0.0f)
2975 {
2976 // Demonstrate a trick: you can use Begin to set yourself in the context of another window
2977 // (here we are already out of your child window)
2978 ImGui::BeginChild("scrolling");
2979 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
2980 ImGui::EndChild();
2981 }
2982 ImGui::Spacing();
2983
2984 static bool show_horizontal_contents_size_demo_window = false;
2985 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
2986
2987 if (show_horizontal_contents_size_demo_window)
2988 {
2989 static bool show_h_scrollbar = true;
2990 static bool show_button = true;
2991 static bool show_tree_nodes = true;
2992 static bool show_text_wrapped = false;
2993 static bool show_columns = true;
2994 static bool show_tab_bar = true;
2995 static bool show_child = false;
2996 static bool explicit_content_size = false;
2997 static float contents_size_x = 300.0f;
2998 if (explicit_content_size)
2999 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
3000 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
3001 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
3002 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
3003 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.");
3004 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
3005 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten)
3006 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width
3007 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
3008 ImGui::Checkbox("Columns", &show_columns); // Will use contents size
3009 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size
3010 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size
3011 ImGui::Checkbox("Explicit content size", &explicit_content_size);
3012 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
3013 if (explicit_content_size)
3014 {
3015 ImGui::SameLine();
3016 ImGui::SetNextItemWidth(100);
3017 ImGui::DragFloat("##csx", &contents_size_x);
3018 ImVec2 p = ImGui::GetCursorScreenPos();
3019 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
3020 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
3021 ImGui::Dummy(ImVec2(0, 10));
3022 }
3023 ImGui::PopStyleVar(2);
3024 ImGui::Separator();
3025 if (show_button)
3026 {
3027 ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
3028 }
3029 if (show_tree_nodes)
3030 {
3031 bool open = true;
3032 if (ImGui::TreeNode("this is a tree node"))
3033 {
3034 if (ImGui::TreeNode("another one of those tree node..."))
3035 {
3036 ImGui::Text("Some tree contents");
3037 ImGui::TreePop();
3038 }
3039 ImGui::TreePop();
3040 }
3041 ImGui::CollapsingHeader("CollapsingHeader", &open);
3042 }
3043 if (show_text_wrapped)
3044 {
3045 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
3046 }
3047 if (show_columns)
3048 {
3049 ImGui::Text("Tables:");
3050 if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders))
3051 {
3052 for (int n = 0; n < 4; n++)
3053 {
3054 ImGui::TableNextColumn();
3055 ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x);
3056 }
3057 ImGui::EndTable();
3058 }
3059 ImGui::Text("Columns:");
3060 ImGui::Columns(4);
3061 for (int n = 0; n < 4; n++)
3062 {
3063 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
3064 ImGui::NextColumn();
3065 }
3066 ImGui::Columns(1);
3067 }
3068 if (show_tab_bar && ImGui::BeginTabBar("Hello"))
3069 {
3070 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
3071 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
3072 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
3073 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
3074 ImGui::EndTabBar();
3075 }
3076 if (show_child)
3077 {
3078 ImGui::BeginChild("child", ImVec2(0, 0), true);
3079 ImGui::EndChild();
3080 }
3081 ImGui::End();
3082 }
3083
3084 ImGui::TreePop();
3085 }
3086
3087 if (ImGui::TreeNode("Clipping"))
3088 {
3089 static ImVec2 size(100.0f, 100.0f);
3090 static ImVec2 offset(30.0f, 30.0f);
3091 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
3092 ImGui::TextWrapped("(Click and drag to scroll)");
3093
3094 for (int n = 0; n < 3; n++)
3095 {
3096 if (n > 0)
3097 ImGui::SameLine();
3098 ImGui::PushID(n);
3099 ImGui::BeginGroup(); // Lock X position
3100
3101 ImGui::InvisibleButton("##empty", size);
3102 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
3103 {
3104 offset.x += ImGui::GetIO().MouseDelta.x;
3105 offset.y += ImGui::GetIO().MouseDelta.y;
3106 }
3107 const ImVec2 p0 = ImGui::GetItemRectMin();
3108 const ImVec2 p1 = ImGui::GetItemRectMax();
3109 const char* text_str = "Line 1 hello\nLine 2 clip me!";
3110 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
3111 ImDrawList* draw_list = ImGui::GetWindowDrawList();
3112
3113 switch (n)
3114 {
3115 case 0:
3116 HelpMarker(
3117 "Using ImGui::PushClipRect():\n"
3118 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
3119 "(use this if you want your clipping rectangle to affect interactions)");
3120 ImGui::PushClipRect(p0, p1, true);
3121 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
3122 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
3123 ImGui::PopClipRect();
3124 break;
3125 case 1:
3126 HelpMarker(
3127 "Using ImDrawList::PushClipRect():\n"
3128 "Will alter ImDrawList rendering only.\n"
3129 "(use this as a shortcut if you are only using ImDrawList calls)");
3130 draw_list->PushClipRect(p0, p1, true);
3131 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
3132 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
3133 draw_list->PopClipRect();
3134 break;
3135 case 2:
3136 HelpMarker(
3137 "Using ImDrawList::AddText() with a fine ClipRect:\n"
3138 "Will alter only this specific ImDrawList::AddText() rendering.\n"
3139 "(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)");
3140 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
3141 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
3142 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
3143 break;
3144 }
3145 ImGui::EndGroup();
3146 ImGui::PopID();
3147 }
3148
3149 ImGui::TreePop();
3150 }
3151 }
3152
ShowDemoWindowPopups()3153 static void ShowDemoWindowPopups()
3154 {
3155 if (!ImGui::CollapsingHeader("Popups & Modal windows"))
3156 return;
3157
3158 // The properties of popups windows are:
3159 // - They block normal mouse hovering detection outside them. (*)
3160 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
3161 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
3162 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
3163 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
3164 // when normally blocked by a popup.
3165 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
3166 // popups at any time.
3167
3168 // Typical use for regular windows:
3169 // 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();
3170 // Typical use for popups:
3171 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
3172
3173 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
3174 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
3175
3176 if (ImGui::TreeNode("Popups"))
3177 {
3178 ImGui::TextWrapped(
3179 "When a popup is active, it inhibits interacting with windows that are behind the popup. "
3180 "Clicking outside the popup closes it.");
3181
3182 static int selected_fish = -1;
3183 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
3184 static bool toggles[] = { true, false, false, false, false };
3185
3186 // Simple selection popup (if you want to show the current selection inside the Button itself,
3187 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
3188 if (ImGui::Button("Select.."))
3189 ImGui::OpenPopup("my_select_popup");
3190 ImGui::SameLine();
3191 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
3192 if (ImGui::BeginPopup("my_select_popup"))
3193 {
3194 ImGui::Text("Aquarium");
3195 ImGui::Separator();
3196 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3197 if (ImGui::Selectable(names[i]))
3198 selected_fish = i;
3199 ImGui::EndPopup();
3200 }
3201
3202 // Showing a menu with toggles
3203 if (ImGui::Button("Toggle.."))
3204 ImGui::OpenPopup("my_toggle_popup");
3205 if (ImGui::BeginPopup("my_toggle_popup"))
3206 {
3207 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3208 ImGui::MenuItem(names[i], "", &toggles[i]);
3209 if (ImGui::BeginMenu("Sub-menu"))
3210 {
3211 ImGui::MenuItem("Click me");
3212 ImGui::EndMenu();
3213 }
3214
3215 ImGui::Separator();
3216 ImGui::Text("Tooltip here");
3217 if (ImGui::IsItemHovered())
3218 ImGui::SetTooltip("I am a tooltip over a popup");
3219
3220 if (ImGui::Button("Stacked Popup"))
3221 ImGui::OpenPopup("another popup");
3222 if (ImGui::BeginPopup("another popup"))
3223 {
3224 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
3225 ImGui::MenuItem(names[i], "", &toggles[i]);
3226 if (ImGui::BeginMenu("Sub-menu"))
3227 {
3228 ImGui::MenuItem("Click me");
3229 if (ImGui::Button("Stacked Popup"))
3230 ImGui::OpenPopup("another popup");
3231 if (ImGui::BeginPopup("another popup"))
3232 {
3233 ImGui::Text("I am the last one here.");
3234 ImGui::EndPopup();
3235 }
3236 ImGui::EndMenu();
3237 }
3238 ImGui::EndPopup();
3239 }
3240 ImGui::EndPopup();
3241 }
3242
3243 // Call the more complete ShowExampleMenuFile which we use in various places of this demo
3244 if (ImGui::Button("File Menu.."))
3245 ImGui::OpenPopup("my_file_popup");
3246 if (ImGui::BeginPopup("my_file_popup"))
3247 {
3248 ShowExampleMenuFile();
3249 ImGui::EndPopup();
3250 }
3251
3252 ImGui::TreePop();
3253 }
3254
3255 if (ImGui::TreeNode("Context menus"))
3256 {
3257 HelpMarker("\"Context\" functions are simple helpers to associate a Popup to a given Item or Window identifier.");
3258
3259 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
3260 // if (id == 0)
3261 // id = GetItemID(); // Use last item id
3262 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
3263 // OpenPopup(id);
3264 // return BeginPopup(id);
3265 // For advanced advanced uses you may want to replicate and customize this code.
3266 // See more details in BeginPopupContextItem().
3267
3268 // Example 1
3269 // When used after an item that has an ID (e.g. Button), we can skip providing an ID to BeginPopupContextItem(),
3270 // and BeginPopupContextItem() will use the last item ID as the popup ID.
3271 {
3272 const char* names[5] = { "Label1", "Label2", "Label3", "Label4", "Label5" };
3273 for (int n = 0; n < 5; n++)
3274 {
3275 ImGui::Selectable(names[n]);
3276 if (ImGui::BeginPopupContextItem()) // <-- use last item id as popup id
3277 {
3278 ImGui::Text("This a popup for \"%s\"!", names[n]);
3279 if (ImGui::Button("Close"))
3280 ImGui::CloseCurrentPopup();
3281 ImGui::EndPopup();
3282 }
3283 if (ImGui::IsItemHovered())
3284 ImGui::SetTooltip("Right-click to open popup");
3285 }
3286 }
3287
3288 // Example 2
3289 // Popup on a Text() element which doesn't have an identifier: we need to provide an identifier to BeginPopupContextItem().
3290 // Using an explicit identifier is also convenient if you want to activate the popups from different locations.
3291 {
3292 HelpMarker("Text() elements don't have stable identifiers so we need to provide one.");
3293 static float value = 0.5f;
3294 ImGui::Text("Value = %.3f <-- (1) right-click this value", value);
3295 if (ImGui::BeginPopupContextItem("my popup"))
3296 {
3297 if (ImGui::Selectable("Set to zero")) value = 0.0f;
3298 if (ImGui::Selectable("Set to PI")) value = 3.1415f;
3299 ImGui::SetNextItemWidth(-FLT_MIN);
3300 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
3301 ImGui::EndPopup();
3302 }
3303
3304 // We can also use OpenPopupOnItemClick() to toggle the visibility of a given popup.
3305 // Here we make it that right-clicking this other text element opens the same popup as above.
3306 // The popup itself will be submitted by the code above.
3307 ImGui::Text("(2) Or right-click this text");
3308 ImGui::OpenPopupOnItemClick("my popup", ImGuiPopupFlags_MouseButtonRight);
3309
3310 // Back to square one: manually open the same popup.
3311 if (ImGui::Button("(3) Or click this button"))
3312 ImGui::OpenPopup("my popup");
3313 }
3314
3315 // Example 3
3316 // When using BeginPopupContextItem() with an implicit identifier (NULL == use last item ID),
3317 // we need to make sure your item identifier is stable.
3318 // In this example we showcase altering the item label while preserving its identifier, using the ### operator (see FAQ).
3319 {
3320 HelpMarker("Showcase using a popup ID linked to item ID, with the item having a changing label + stable ID using the ### operator.");
3321 static char name[32] = "Label1";
3322 char buf[64];
3323 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
3324 ImGui::Button(buf);
3325 if (ImGui::BeginPopupContextItem())
3326 {
3327 ImGui::Text("Edit name:");
3328 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
3329 if (ImGui::Button("Close"))
3330 ImGui::CloseCurrentPopup();
3331 ImGui::EndPopup();
3332 }
3333 ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
3334 }
3335
3336 ImGui::TreePop();
3337 }
3338
3339 if (ImGui::TreeNode("Modals"))
3340 {
3341 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
3342
3343 if (ImGui::Button("Delete.."))
3344 ImGui::OpenPopup("Delete?");
3345
3346 // Always center this window when appearing
3347 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
3348 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
3349
3350 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
3351 {
3352 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
3353 ImGui::Separator();
3354
3355 //static int unused_i = 0;
3356 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
3357
3358 static bool dont_ask_me_next_time = false;
3359 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3360 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
3361 ImGui::PopStyleVar();
3362
3363 if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3364 ImGui::SetItemDefaultFocus();
3365 ImGui::SameLine();
3366 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
3367 ImGui::EndPopup();
3368 }
3369
3370 if (ImGui::Button("Stacked modals.."))
3371 ImGui::OpenPopup("Stacked 1");
3372 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
3373 {
3374 if (ImGui::BeginMenuBar())
3375 {
3376 if (ImGui::BeginMenu("File"))
3377 {
3378 if (ImGui::MenuItem("Some menu item")) {}
3379 ImGui::EndMenu();
3380 }
3381 ImGui::EndMenuBar();
3382 }
3383 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
3384
3385 // Testing behavior of widgets stacking their own regular popups over the modal.
3386 static int item = 1;
3387 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
3388 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
3389 ImGui::ColorEdit4("color", color);
3390
3391 if (ImGui::Button("Add another modal.."))
3392 ImGui::OpenPopup("Stacked 2");
3393
3394 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
3395 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
3396 // of the bool actually doesn't matter here.
3397 bool unused_open = true;
3398 if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
3399 {
3400 ImGui::Text("Hello from Stacked The Second!");
3401 if (ImGui::Button("Close"))
3402 ImGui::CloseCurrentPopup();
3403 ImGui::EndPopup();
3404 }
3405
3406 if (ImGui::Button("Close"))
3407 ImGui::CloseCurrentPopup();
3408 ImGui::EndPopup();
3409 }
3410
3411 ImGui::TreePop();
3412 }
3413
3414 if (ImGui::TreeNode("Menus inside a regular window"))
3415 {
3416 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
3417 ImGui::Separator();
3418
3419 // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the
3420 // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block
3421 // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would
3422 // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it,
3423 // which is the desired behavior for regular menus.
3424 ImGui::PushID("foo");
3425 ImGui::MenuItem("Menu item", "CTRL+M");
3426 if (ImGui::BeginMenu("Menu inside a regular window"))
3427 {
3428 ShowExampleMenuFile();
3429 ImGui::EndMenu();
3430 }
3431 ImGui::PopID();
3432 ImGui::Separator();
3433 ImGui::TreePop();
3434 }
3435 }
3436
3437 // Dummy data structure that we use for the Table demo.
3438 // (pre-C++11 doesn't allow us to instantiate ImVector<MyItem> template if this structure if defined inside the demo function)
3439 namespace
3440 {
3441 // We are passing our own identifier to TableSetupColumn() to facilitate identifying columns in the sorting code.
3442 // This identifier will be passed down into ImGuiTableSortSpec::ColumnUserID.
3443 // But it is possible to omit the user id parameter of TableSetupColumn() and just use the column index instead! (ImGuiTableSortSpec::ColumnIndex)
3444 // If you don't use sorting, you will generally never care about giving column an ID!
3445 enum MyItemColumnID
3446 {
3447 MyItemColumnID_ID,
3448 MyItemColumnID_Name,
3449 MyItemColumnID_Action,
3450 MyItemColumnID_Quantity,
3451 MyItemColumnID_Description
3452 };
3453
3454 struct MyItem
3455 {
3456 int ID;
3457 const char* Name;
3458 int Quantity;
3459
3460 // We have a problem which is affecting _only this demo_ and should not affect your code:
3461 // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(),
3462 // however qsort doesn't allow passing user data to comparing function.
3463 // As a workaround, we are storing the sort specs in a static/global for the comparing function to access.
3464 // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global.
3465 // We could technically call ImGui::TableGetSortSpecs() in CompareWithSortSpecs(), but considering that this function is called
3466 // very often by the sorting algorithm it would be a little wasteful.
3467 static const ImGuiTableSortSpecs* s_current_sort_specs;
3468
3469 // Compare function to be used by qsort()
CompareWithSortSpecs__anon8f8eb64f0111::MyItem3470 static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
3471 {
3472 const MyItem* a = (const MyItem*)lhs;
3473 const MyItem* b = (const MyItem*)rhs;
3474 for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
3475 {
3476 // Here we identify columns using the ColumnUserID value that we ourselves passed to TableSetupColumn()
3477 // We could also choose to identify columns based on their index (sort_spec->ColumnIndex), which is simpler!
3478 const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
3479 int delta = 0;
3480 switch (sort_spec->ColumnUserID)
3481 {
3482 case MyItemColumnID_ID: delta = (a->ID - b->ID); break;
3483 case MyItemColumnID_Name: delta = (strcmp(a->Name, b->Name)); break;
3484 case MyItemColumnID_Quantity: delta = (a->Quantity - b->Quantity); break;
3485 case MyItemColumnID_Description: delta = (strcmp(a->Name, b->Name)); break;
3486 default: IM_ASSERT(0); break;
3487 }
3488 if (delta > 0)
3489 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
3490 if (delta < 0)
3491 return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
3492 }
3493
3494 // qsort() is instable so always return a way to differenciate items.
3495 // Your own compare function may want to avoid fallback on implicit sort specs e.g. a Name compare if it wasn't already part of the sort specs.
3496 return (a->ID - b->ID);
3497 }
3498 };
3499 const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
3500 }
3501
3502 // Make the UI compact because there are so many fields
PushStyleCompact()3503 static void PushStyleCompact()
3504 {
3505 ImGuiStyle& style = ImGui::GetStyle();
3506 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f)));
3507 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f)));
3508 }
3509
PopStyleCompact()3510 static void PopStyleCompact()
3511 {
3512 ImGui::PopStyleVar(2);
3513 }
3514
3515 // Show a combo box with a choice of sizing policies
EditTableSizingFlags(ImGuiTableFlags * p_flags)3516 static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
3517 {
3518 struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
3519 static const EnumDesc policies[] =
3520 {
3521 { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." },
3522 { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
3523 { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
3524 { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
3525 { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
3526 };
3527 int idx;
3528 for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
3529 if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
3530 break;
3531 const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
3532 if (ImGui::BeginCombo("Sizing Policy", preview_text))
3533 {
3534 for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
3535 if (ImGui::Selectable(policies[n].Name, idx == n))
3536 *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
3537 ImGui::EndCombo();
3538 }
3539 ImGui::SameLine();
3540 ImGui::TextDisabled("(?)");
3541 if (ImGui::IsItemHovered())
3542 {
3543 ImGui::BeginTooltip();
3544 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
3545 for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
3546 {
3547 ImGui::Separator();
3548 ImGui::Text("%s:", policies[m].Name);
3549 ImGui::Separator();
3550 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
3551 ImGui::TextUnformatted(policies[m].Tooltip);
3552 }
3553 ImGui::PopTextWrapPos();
3554 ImGui::EndTooltip();
3555 }
3556 }
3557
EditTableColumnsFlags(ImGuiTableColumnFlags * p_flags)3558 static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
3559 {
3560 ImGui::CheckboxFlags("_Disabled", p_flags, ImGuiTableColumnFlags_Disabled); ImGui::SameLine(); HelpMarker("Master disable flag (also hide from context menu)");
3561 ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
3562 ImGui::CheckboxFlags("_DefaultSort", p_flags, ImGuiTableColumnFlags_DefaultSort);
3563 if (ImGui::CheckboxFlags("_WidthStretch", p_flags, ImGuiTableColumnFlags_WidthStretch))
3564 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
3565 if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
3566 *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
3567 ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
3568 ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
3569 ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
3570 ImGui::CheckboxFlags("_NoClip", p_flags, ImGuiTableColumnFlags_NoClip);
3571 ImGui::CheckboxFlags("_NoSort", p_flags, ImGuiTableColumnFlags_NoSort);
3572 ImGui::CheckboxFlags("_NoSortAscending", p_flags, ImGuiTableColumnFlags_NoSortAscending);
3573 ImGui::CheckboxFlags("_NoSortDescending", p_flags, ImGuiTableColumnFlags_NoSortDescending);
3574 ImGui::CheckboxFlags("_NoHeaderLabel", p_flags, ImGuiTableColumnFlags_NoHeaderLabel);
3575 ImGui::CheckboxFlags("_NoHeaderWidth", p_flags, ImGuiTableColumnFlags_NoHeaderWidth);
3576 ImGui::CheckboxFlags("_PreferSortAscending", p_flags, ImGuiTableColumnFlags_PreferSortAscending);
3577 ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
3578 ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
3579 ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
3580 }
3581
ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)3582 static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
3583 {
3584 ImGui::CheckboxFlags("_IsEnabled", &flags, ImGuiTableColumnFlags_IsEnabled);
3585 ImGui::CheckboxFlags("_IsVisible", &flags, ImGuiTableColumnFlags_IsVisible);
3586 ImGui::CheckboxFlags("_IsSorted", &flags, ImGuiTableColumnFlags_IsSorted);
3587 ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
3588 }
3589
ShowDemoWindowTables()3590 static void ShowDemoWindowTables()
3591 {
3592 //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
3593 if (!ImGui::CollapsingHeader("Tables & Columns"))
3594 return;
3595
3596 // Using those as a base value to create width/height that are factor of the size of our font
3597 const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
3598 const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
3599
3600 ImGui::PushID("Tables");
3601
3602 int open_action = -1;
3603 if (ImGui::Button("Open all"))
3604 open_action = 1;
3605 ImGui::SameLine();
3606 if (ImGui::Button("Close all"))
3607 open_action = 0;
3608 ImGui::SameLine();
3609
3610 // Options
3611 static bool disable_indent = false;
3612 ImGui::Checkbox("Disable tree indentation", &disable_indent);
3613 ImGui::SameLine();
3614 HelpMarker("Disable the indenting of tree nodes so demo tables can use the full window width.");
3615 ImGui::Separator();
3616 if (disable_indent)
3617 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
3618
3619 // About Styling of tables
3620 // Most settings are configured on a per-table basis via the flags passed to BeginTable() and TableSetupColumns APIs.
3621 // There are however a few settings that a shared and part of the ImGuiStyle structure:
3622 // style.CellPadding // Padding within each cell
3623 // style.Colors[ImGuiCol_TableHeaderBg] // Table header background
3624 // style.Colors[ImGuiCol_TableBorderStrong] // Table outer and header borders
3625 // style.Colors[ImGuiCol_TableBorderLight] // Table inner borders
3626 // style.Colors[ImGuiCol_TableRowBg] // Table row background when ImGuiTableFlags_RowBg is enabled (even rows)
3627 // style.Colors[ImGuiCol_TableRowBgAlt] // Table row background when ImGuiTableFlags_RowBg is enabled (odds rows)
3628
3629 // Demos
3630 if (open_action != -1)
3631 ImGui::SetNextItemOpen(open_action != 0);
3632 if (ImGui::TreeNode("Basic"))
3633 {
3634 // Here we will showcase three different ways to output a table.
3635 // They are very simple variations of a same thing!
3636
3637 // [Method 1] Using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
3638 // In many situations, this is the most flexible and easy to use pattern.
3639 HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
3640 if (ImGui::BeginTable("table1", 3))
3641 {
3642 for (int row = 0; row < 4; row++)
3643 {
3644 ImGui::TableNextRow();
3645 for (int column = 0; column < 3; column++)
3646 {
3647 ImGui::TableSetColumnIndex(column);
3648 ImGui::Text("Row %d Column %d", row, column);
3649 }
3650 }
3651 ImGui::EndTable();
3652 }
3653
3654 // [Method 2] Using TableNextColumn() called multiple times, instead of using a for loop + TableSetColumnIndex().
3655 // This is generally more convenient when you have code manually submitting the contents of each columns.
3656 HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
3657 if (ImGui::BeginTable("table2", 3))
3658 {
3659 for (int row = 0; row < 4; row++)
3660 {
3661 ImGui::TableNextRow();
3662 ImGui::TableNextColumn();
3663 ImGui::Text("Row %d", row);
3664 ImGui::TableNextColumn();
3665 ImGui::Text("Some contents");
3666 ImGui::TableNextColumn();
3667 ImGui::Text("123.456");
3668 }
3669 ImGui::EndTable();
3670 }
3671
3672 // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(),
3673 // as TableNextColumn() will automatically wrap around and create new roes as needed.
3674 // This is generally more convenient when your cells all contains the same type of data.
3675 HelpMarker(
3676 "Only using TableNextColumn(), which tends to be convenient for tables where every cells contains the same type of contents.\n"
3677 "This is also more similar to the old NextColumn() function of the Columns API, and provided to facilitate the Columns->Tables API transition.");
3678 if (ImGui::BeginTable("table3", 3))
3679 {
3680 for (int item = 0; item < 14; item++)
3681 {
3682 ImGui::TableNextColumn();
3683 ImGui::Text("Item %d", item);
3684 }
3685 ImGui::EndTable();
3686 }
3687
3688 ImGui::TreePop();
3689 }
3690
3691 if (open_action != -1)
3692 ImGui::SetNextItemOpen(open_action != 0);
3693 if (ImGui::TreeNode("Borders, background"))
3694 {
3695 // Expose a few Borders related flags interactively
3696 enum ContentsType { CT_Text, CT_FillButton };
3697 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
3698 static bool display_headers = false;
3699 static int contents_type = CT_Text;
3700
3701 PushStyleCompact();
3702 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
3703 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
3704 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterH");
3705 ImGui::Indent();
3706
3707 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
3708 ImGui::Indent();
3709 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
3710 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
3711 ImGui::Unindent();
3712
3713 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
3714 ImGui::Indent();
3715 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
3716 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
3717 ImGui::Unindent();
3718
3719 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
3720 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
3721 ImGui::Unindent();
3722
3723 ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
3724 ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
3725 ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
3726 ImGui::Checkbox("Display headers", &display_headers);
3727 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers");
3728 PopStyleCompact();
3729
3730 if (ImGui::BeginTable("table1", 3, flags))
3731 {
3732 // Display headers so we can inspect their interaction with borders.
3733 // (Headers are not the main purpose of this section of the demo, so we are not elaborating on them too much. See other sections for details)
3734 if (display_headers)
3735 {
3736 ImGui::TableSetupColumn("One");
3737 ImGui::TableSetupColumn("Two");
3738 ImGui::TableSetupColumn("Three");
3739 ImGui::TableHeadersRow();
3740 }
3741
3742 for (int row = 0; row < 5; row++)
3743 {
3744 ImGui::TableNextRow();
3745 for (int column = 0; column < 3; column++)
3746 {
3747 ImGui::TableSetColumnIndex(column);
3748 char buf[32];
3749 sprintf(buf, "Hello %d,%d", column, row);
3750 if (contents_type == CT_Text)
3751 ImGui::TextUnformatted(buf);
3752 else if (contents_type)
3753 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
3754 }
3755 }
3756 ImGui::EndTable();
3757 }
3758 ImGui::TreePop();
3759 }
3760
3761 if (open_action != -1)
3762 ImGui::SetNextItemOpen(open_action != 0);
3763 if (ImGui::TreeNode("Resizable, stretch"))
3764 {
3765 // By default, if we don't enable ScrollX the sizing policy for each columns is "Stretch"
3766 // Each columns maintain a sizing weight, and they will occupy all available width.
3767 static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
3768 PushStyleCompact();
3769 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
3770 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
3771 ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersInnerV flag as well, this is why the resize borders are still showing when unchecking this.");
3772 PopStyleCompact();
3773
3774 if (ImGui::BeginTable("table1", 3, flags))
3775 {
3776 for (int row = 0; row < 5; row++)
3777 {
3778 ImGui::TableNextRow();
3779 for (int column = 0; column < 3; column++)
3780 {
3781 ImGui::TableSetColumnIndex(column);
3782 ImGui::Text("Hello %d,%d", column, row);
3783 }
3784 }
3785 ImGui::EndTable();
3786 }
3787 ImGui::TreePop();
3788 }
3789
3790 if (open_action != -1)
3791 ImGui::SetNextItemOpen(open_action != 0);
3792 if (ImGui::TreeNode("Resizable, fixed"))
3793 {
3794 // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
3795 // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
3796 // If there is not enough available width to fit all columns, they will however be resized down.
3797 // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
3798 HelpMarker(
3799 "Using _Resizable + _SizingFixedFit flags.\n"
3800 "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
3801 "Double-click a column border to auto-fit the column to its contents.");
3802 PushStyleCompact();
3803 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
3804 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
3805 PopStyleCompact();
3806
3807 if (ImGui::BeginTable("table1", 3, flags))
3808 {
3809 for (int row = 0; row < 5; row++)
3810 {
3811 ImGui::TableNextRow();
3812 for (int column = 0; column < 3; column++)
3813 {
3814 ImGui::TableSetColumnIndex(column);
3815 ImGui::Text("Hello %d,%d", column, row);
3816 }
3817 }
3818 ImGui::EndTable();
3819 }
3820 ImGui::TreePop();
3821 }
3822
3823 if (open_action != -1)
3824 ImGui::SetNextItemOpen(open_action != 0);
3825 if (ImGui::TreeNode("Resizable, mixed"))
3826 {
3827 HelpMarker(
3828 "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
3829 "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
3830 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
3831
3832 if (ImGui::BeginTable("table1", 3, flags))
3833 {
3834 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
3835 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
3836 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthStretch);
3837 ImGui::TableHeadersRow();
3838 for (int row = 0; row < 5; row++)
3839 {
3840 ImGui::TableNextRow();
3841 for (int column = 0; column < 3; column++)
3842 {
3843 ImGui::TableSetColumnIndex(column);
3844 ImGui::Text("%s %d,%d", (column == 2) ? "Stretch" : "Fixed", column, row);
3845 }
3846 }
3847 ImGui::EndTable();
3848 }
3849 if (ImGui::BeginTable("table2", 6, flags))
3850 {
3851 ImGui::TableSetupColumn("AAA", ImGuiTableColumnFlags_WidthFixed);
3852 ImGui::TableSetupColumn("BBB", ImGuiTableColumnFlags_WidthFixed);
3853 ImGui::TableSetupColumn("CCC", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_DefaultHide);
3854 ImGui::TableSetupColumn("DDD", ImGuiTableColumnFlags_WidthStretch);
3855 ImGui::TableSetupColumn("EEE", ImGuiTableColumnFlags_WidthStretch);
3856 ImGui::TableSetupColumn("FFF", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultHide);
3857 ImGui::TableHeadersRow();
3858 for (int row = 0; row < 5; row++)
3859 {
3860 ImGui::TableNextRow();
3861 for (int column = 0; column < 6; column++)
3862 {
3863 ImGui::TableSetColumnIndex(column);
3864 ImGui::Text("%s %d,%d", (column >= 3) ? "Stretch" : "Fixed", column, row);
3865 }
3866 }
3867 ImGui::EndTable();
3868 }
3869 ImGui::TreePop();
3870 }
3871
3872 if (open_action != -1)
3873 ImGui::SetNextItemOpen(open_action != 0);
3874 if (ImGui::TreeNode("Reorderable, hideable, with headers"))
3875 {
3876 HelpMarker(
3877 "Click and drag column headers to reorder columns.\n\n"
3878 "Right-click on a header to open a context menu.");
3879 static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
3880 PushStyleCompact();
3881 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
3882 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
3883 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
3884 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody);
3885 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers)");
3886 PopStyleCompact();
3887
3888 if (ImGui::BeginTable("table1", 3, flags))
3889 {
3890 // Submit columns name with TableSetupColumn() and call TableHeadersRow() to create a row with a header in each column.
3891 // (Later we will show how TableSetupColumn() has other uses, optional flags, sizing weight etc.)
3892 ImGui::TableSetupColumn("One");
3893 ImGui::TableSetupColumn("Two");
3894 ImGui::TableSetupColumn("Three");
3895 ImGui::TableHeadersRow();
3896 for (int row = 0; row < 6; row++)
3897 {
3898 ImGui::TableNextRow();
3899 for (int column = 0; column < 3; column++)
3900 {
3901 ImGui::TableSetColumnIndex(column);
3902 ImGui::Text("Hello %d,%d", column, row);
3903 }
3904 }
3905 ImGui::EndTable();
3906 }
3907
3908 // Use outer_size.x == 0.0f instead of default to make the table as tight as possible (only valid when no scrolling and no stretch column)
3909 if (ImGui::BeginTable("table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
3910 {
3911 ImGui::TableSetupColumn("One");
3912 ImGui::TableSetupColumn("Two");
3913 ImGui::TableSetupColumn("Three");
3914 ImGui::TableHeadersRow();
3915 for (int row = 0; row < 6; row++)
3916 {
3917 ImGui::TableNextRow();
3918 for (int column = 0; column < 3; column++)
3919 {
3920 ImGui::TableSetColumnIndex(column);
3921 ImGui::Text("Fixed %d,%d", column, row);
3922 }
3923 }
3924 ImGui::EndTable();
3925 }
3926 ImGui::TreePop();
3927 }
3928
3929 if (open_action != -1)
3930 ImGui::SetNextItemOpen(open_action != 0);
3931 if (ImGui::TreeNode("Padding"))
3932 {
3933 // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
3934 // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
3935 HelpMarker(
3936 "We often want outer padding activated when any using features which makes the edges of a column visible:\n"
3937 "e.g.:\n"
3938 "- BorderOuterV\n"
3939 "- any form of row selection\n"
3940 "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n"
3941 "Actual padding values are using style.CellPadding.\n\n"
3942 "In this demo we don't show horizontal borders to emphasis how they don't affect default horizontal padding.");
3943
3944 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
3945 PushStyleCompact();
3946 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
3947 ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
3948 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
3949 ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
3950 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
3951 ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
3952 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
3953 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
3954 static bool show_headers = false;
3955 ImGui::Checkbox("show_headers", &show_headers);
3956 PopStyleCompact();
3957
3958 if (ImGui::BeginTable("table_padding", 3, flags1))
3959 {
3960 if (show_headers)
3961 {
3962 ImGui::TableSetupColumn("One");
3963 ImGui::TableSetupColumn("Two");
3964 ImGui::TableSetupColumn("Three");
3965 ImGui::TableHeadersRow();
3966 }
3967
3968 for (int row = 0; row < 5; row++)
3969 {
3970 ImGui::TableNextRow();
3971 for (int column = 0; column < 3; column++)
3972 {
3973 ImGui::TableSetColumnIndex(column);
3974 if (row == 0)
3975 {
3976 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
3977 }
3978 else
3979 {
3980 char buf[32];
3981 sprintf(buf, "Hello %d,%d", column, row);
3982 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
3983 }
3984 //if (ImGui::TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered)
3985 // ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, IM_COL32(0, 100, 0, 255));
3986 }
3987 }
3988 ImGui::EndTable();
3989 }
3990
3991 // Second example: set style.CellPadding to (0.0) or a custom value.
3992 // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
3993 HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
3994 static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
3995 static ImVec2 cell_padding(0.0f, 0.0f);
3996 static bool show_widget_frame_bg = true;
3997
3998 PushStyleCompact();
3999 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
4000 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
4001 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
4002 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
4003 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
4004 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
4005 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
4006 ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
4007 ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
4008 PopStyleCompact();
4009
4010 ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
4011 if (ImGui::BeginTable("table_padding_2", 3, flags2))
4012 {
4013 static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
4014 static bool init = true;
4015 if (!show_widget_frame_bg)
4016 ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
4017 for (int cell = 0; cell < 3 * 5; cell++)
4018 {
4019 ImGui::TableNextColumn();
4020 if (init)
4021 strcpy(text_bufs[cell], "edit me");
4022 ImGui::SetNextItemWidth(-FLT_MIN);
4023 ImGui::PushID(cell);
4024 ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
4025 ImGui::PopID();
4026 }
4027 if (!show_widget_frame_bg)
4028 ImGui::PopStyleColor();
4029 init = false;
4030 ImGui::EndTable();
4031 }
4032 ImGui::PopStyleVar();
4033
4034 ImGui::TreePop();
4035 }
4036
4037 if (open_action != -1)
4038 ImGui::SetNextItemOpen(open_action != 0);
4039 if (ImGui::TreeNode("Sizing policies"))
4040 {
4041 static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
4042 PushStyleCompact();
4043 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
4044 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags1, ImGuiTableFlags_NoHostExtendX);
4045 PopStyleCompact();
4046
4047 static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
4048 for (int table_n = 0; table_n < 4; table_n++)
4049 {
4050 ImGui::PushID(table_n);
4051 ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
4052 EditTableSizingFlags(&sizing_policy_flags[table_n]);
4053
4054 // To make it easier to understand the different sizing policy,
4055 // For each policy: we display one table where the columns have equal contents width, and one where the columns have different contents width.
4056 if (ImGui::BeginTable("table1", 3, sizing_policy_flags[table_n] | flags1))
4057 {
4058 for (int row = 0; row < 3; row++)
4059 {
4060 ImGui::TableNextRow();
4061 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
4062 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
4063 ImGui::TableNextColumn(); ImGui::Text("Oh dear");
4064 }
4065 ImGui::EndTable();
4066 }
4067 if (ImGui::BeginTable("table2", 3, sizing_policy_flags[table_n] | flags1))
4068 {
4069 for (int row = 0; row < 3; row++)
4070 {
4071 ImGui::TableNextRow();
4072 ImGui::TableNextColumn(); ImGui::Text("AAAA");
4073 ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
4074 ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
4075 }
4076 ImGui::EndTable();
4077 }
4078 ImGui::PopID();
4079 }
4080
4081 ImGui::Spacing();
4082 ImGui::TextUnformatted("Advanced");
4083 ImGui::SameLine();
4084 HelpMarker("This section allows you to interact and see the effect of various sizing policies depending on whether Scroll is enabled and the contents of your columns.");
4085
4086 enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
4087 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
4088 static int contents_type = CT_ShowWidth;
4089 static int column_count = 3;
4090
4091 PushStyleCompact();
4092 ImGui::PushID("Advanced");
4093 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
4094 EditTableSizingFlags(&flags);
4095 ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
4096 if (contents_type == CT_FillButton)
4097 {
4098 ImGui::SameLine();
4099 HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width.");
4100 }
4101 ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
4102 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
4103 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
4104 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
4105 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
4106 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
4107 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
4108 ImGui::PopItemWidth();
4109 ImGui::PopID();
4110 PopStyleCompact();
4111
4112 if (ImGui::BeginTable("table2", column_count, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 7)))
4113 {
4114 for (int cell = 0; cell < 10 * column_count; cell++)
4115 {
4116 ImGui::TableNextColumn();
4117 int column = ImGui::TableGetColumnIndex();
4118 int row = ImGui::TableGetRowIndex();
4119
4120 ImGui::PushID(cell);
4121 char label[32];
4122 static char text_buf[32] = "";
4123 sprintf(label, "Hello %d,%d", column, row);
4124 switch (contents_type)
4125 {
4126 case CT_ShortText: ImGui::TextUnformatted(label); break;
4127 case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
4128 case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
4129 case CT_Button: ImGui::Button(label); break;
4130 case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
4131 case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
4132 }
4133 ImGui::PopID();
4134 }
4135 ImGui::EndTable();
4136 }
4137 ImGui::TreePop();
4138 }
4139
4140 if (open_action != -1)
4141 ImGui::SetNextItemOpen(open_action != 0);
4142 if (ImGui::TreeNode("Vertical scrolling, with clipping"))
4143 {
4144 HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\nWe also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
4145 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4146
4147 PushStyleCompact();
4148 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
4149 PopStyleCompact();
4150
4151 // When using ScrollX or ScrollY we need to specify a size for our table container!
4152 // Otherwise by default the table will fit all available space, like a BeginChild() call.
4153 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
4154 if (ImGui::BeginTable("table_scrolly", 3, flags, outer_size))
4155 {
4156 ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
4157 ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None);
4158 ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
4159 ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
4160 ImGui::TableHeadersRow();
4161
4162 // Demonstrate using clipper for large vertical lists
4163 ImGuiListClipper clipper;
4164 clipper.Begin(1000);
4165 while (clipper.Step())
4166 {
4167 for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
4168 {
4169 ImGui::TableNextRow();
4170 for (int column = 0; column < 3; column++)
4171 {
4172 ImGui::TableSetColumnIndex(column);
4173 ImGui::Text("Hello %d,%d", column, row);
4174 }
4175 }
4176 }
4177 ImGui::EndTable();
4178 }
4179 ImGui::TreePop();
4180 }
4181
4182 if (open_action != -1)
4183 ImGui::SetNextItemOpen(open_action != 0);
4184 if (ImGui::TreeNode("Horizontal scrolling"))
4185 {
4186 HelpMarker(
4187 "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
4188 "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
4189 "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX,"
4190 "because the container window won't automatically extend vertically to fix contents (this may be improved in future versions).");
4191 static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
4192 static int freeze_cols = 1;
4193 static int freeze_rows = 1;
4194
4195 PushStyleCompact();
4196 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
4197 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
4198 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
4199 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
4200 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
4201 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
4202 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
4203 PopStyleCompact();
4204
4205 // When using ScrollX or ScrollY we need to specify a size for our table container!
4206 // Otherwise by default the table will fit all available space, like a BeginChild() call.
4207 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 8);
4208 if (ImGui::BeginTable("table_scrollx", 7, flags, outer_size))
4209 {
4210 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
4211 ImGui::TableSetupColumn("Line #", ImGuiTableColumnFlags_NoHide); // Make the first column not hideable to match our use of TableSetupScrollFreeze()
4212 ImGui::TableSetupColumn("One");
4213 ImGui::TableSetupColumn("Two");
4214 ImGui::TableSetupColumn("Three");
4215 ImGui::TableSetupColumn("Four");
4216 ImGui::TableSetupColumn("Five");
4217 ImGui::TableSetupColumn("Six");
4218 ImGui::TableHeadersRow();
4219 for (int row = 0; row < 20; row++)
4220 {
4221 ImGui::TableNextRow();
4222 for (int column = 0; column < 7; column++)
4223 {
4224 // Both TableNextColumn() and TableSetColumnIndex() return true when a column is visible or performing width measurement.
4225 // Because here we know that:
4226 // - A) all our columns are contributing the same to row height
4227 // - B) column 0 is always visible,
4228 // We only always submit this one column and can skip others.
4229 // More advanced per-column clipping behaviors may benefit from polling the status flags via TableGetColumnFlags().
4230 if (!ImGui::TableSetColumnIndex(column) && column > 0)
4231 continue;
4232 if (column == 0)
4233 ImGui::Text("Line %d", row);
4234 else
4235 ImGui::Text("Hello world %d,%d", column, row);
4236 }
4237 }
4238 ImGui::EndTable();
4239 }
4240
4241 ImGui::Spacing();
4242 ImGui::TextUnformatted("Stretch + ScrollX");
4243 ImGui::SameLine();
4244 HelpMarker(
4245 "Showcase using Stretch columns + ScrollX together: "
4246 "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
4247 "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense.");
4248 static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
4249 static float inner_width = 1000.0f;
4250 PushStyleCompact();
4251 ImGui::PushID("flags3");
4252 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
4253 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
4254 ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
4255 ImGui::PopItemWidth();
4256 ImGui::PopID();
4257 PopStyleCompact();
4258 if (ImGui::BeginTable("table2", 7, flags2, outer_size, inner_width))
4259 {
4260 for (int cell = 0; cell < 20 * 7; cell++)
4261 {
4262 ImGui::TableNextColumn();
4263 ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
4264 }
4265 ImGui::EndTable();
4266 }
4267 ImGui::TreePop();
4268 }
4269
4270 if (open_action != -1)
4271 ImGui::SetNextItemOpen(open_action != 0);
4272 if (ImGui::TreeNode("Columns flags"))
4273 {
4274 // Create a first table just to show all the options/flags we want to make visible in our example!
4275 const int column_count = 3;
4276 const char* column_names[column_count] = { "One", "Two", "Three" };
4277 static ImGuiTableColumnFlags column_flags[column_count] = { ImGuiTableColumnFlags_DefaultSort, ImGuiTableColumnFlags_None, ImGuiTableColumnFlags_DefaultHide };
4278 static ImGuiTableColumnFlags column_flags_out[column_count] = { 0, 0, 0 }; // Output from TableGetColumnFlags()
4279
4280 if (ImGui::BeginTable("table_columns_flags_checkboxes", column_count, ImGuiTableFlags_None))
4281 {
4282 PushStyleCompact();
4283 for (int column = 0; column < column_count; column++)
4284 {
4285 ImGui::TableNextColumn();
4286 ImGui::PushID(column);
4287 ImGui::AlignTextToFramePadding(); // FIXME-TABLE: Workaround for wrong text baseline propagation
4288 ImGui::Text("'%s'", column_names[column]);
4289 ImGui::Spacing();
4290 ImGui::Text("Input flags:");
4291 EditTableColumnsFlags(&column_flags[column]);
4292 ImGui::Spacing();
4293 ImGui::Text("Output flags:");
4294 ShowTableColumnsStatusFlags(column_flags_out[column]);
4295 ImGui::PopID();
4296 }
4297 PopStyleCompact();
4298 ImGui::EndTable();
4299 }
4300
4301 // Create the real table we care about for the example!
4302 // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, otherwise in
4303 // a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + resizing the parent window down)
4304 const ImGuiTableFlags flags
4305 = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
4306 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
4307 | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
4308 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
4309 if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
4310 {
4311 for (int column = 0; column < column_count; column++)
4312 ImGui::TableSetupColumn(column_names[column], column_flags[column]);
4313 ImGui::TableHeadersRow();
4314 for (int column = 0; column < column_count; column++)
4315 column_flags_out[column] = ImGui::TableGetColumnFlags(column);
4316 float indent_step = (float)((int)TEXT_BASE_WIDTH / 2);
4317 for (int row = 0; row < 8; row++)
4318 {
4319 ImGui::Indent(indent_step); // Add some indentation to demonstrate usage of per-column IndentEnable/IndentDisable flags.
4320 ImGui::TableNextRow();
4321 for (int column = 0; column < column_count; column++)
4322 {
4323 ImGui::TableSetColumnIndex(column);
4324 ImGui::Text("%s %s", (column == 0) ? "Indented" : "Hello", ImGui::TableGetColumnName(column));
4325 }
4326 }
4327 ImGui::Unindent(indent_step * 8.0f);
4328
4329 ImGui::EndTable();
4330 }
4331 ImGui::TreePop();
4332 }
4333
4334 if (open_action != -1)
4335 ImGui::SetNextItemOpen(open_action != 0);
4336 if (ImGui::TreeNode("Columns widths"))
4337 {
4338 HelpMarker("Using TableSetupColumn() to setup default width.");
4339
4340 static ImGuiTableFlags flags1 = ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBodyUntilResize;
4341 PushStyleCompact();
4342 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
4343 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags1, ImGuiTableFlags_NoBordersInBodyUntilResize);
4344 PopStyleCompact();
4345 if (ImGui::BeginTable("table1", 3, flags1))
4346 {
4347 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
4348 ImGui::TableSetupColumn("one", ImGuiTableColumnFlags_WidthFixed, 100.0f); // Default to 100.0f
4349 ImGui::TableSetupColumn("two", ImGuiTableColumnFlags_WidthFixed, 200.0f); // Default to 200.0f
4350 ImGui::TableSetupColumn("three", ImGuiTableColumnFlags_WidthFixed); // Default to auto
4351 ImGui::TableHeadersRow();
4352 for (int row = 0; row < 4; row++)
4353 {
4354 ImGui::TableNextRow();
4355 for (int column = 0; column < 3; column++)
4356 {
4357 ImGui::TableSetColumnIndex(column);
4358 if (row == 0)
4359 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
4360 else
4361 ImGui::Text("Hello %d,%d", column, row);
4362 }
4363 }
4364 ImGui::EndTable();
4365 }
4366
4367 HelpMarker("Using TableSetupColumn() to setup explicit width.\n\nUnless _NoKeepColumnsVisible is set, fixed columns with set width may still be shrunk down if there's not enough space in the host.");
4368
4369 static ImGuiTableFlags flags2 = ImGuiTableFlags_None;
4370 PushStyleCompact();
4371 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags2, ImGuiTableFlags_NoKeepColumnsVisible);
4372 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags2, ImGuiTableFlags_BordersInnerV);
4373 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags2, ImGuiTableFlags_BordersOuterV);
4374 PopStyleCompact();
4375 if (ImGui::BeginTable("table2", 4, flags2))
4376 {
4377 // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
4378 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
4379 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
4380 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
4381 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
4382 for (int row = 0; row < 5; row++)
4383 {
4384 ImGui::TableNextRow();
4385 for (int column = 0; column < 4; column++)
4386 {
4387 ImGui::TableSetColumnIndex(column);
4388 if (row == 0)
4389 ImGui::Text("(w: %5.1f)", ImGui::GetContentRegionAvail().x);
4390 else
4391 ImGui::Text("Hello %d,%d", column, row);
4392 }
4393 }
4394 ImGui::EndTable();
4395 }
4396 ImGui::TreePop();
4397 }
4398
4399 if (open_action != -1)
4400 ImGui::SetNextItemOpen(open_action != 0);
4401 if (ImGui::TreeNode("Nested tables"))
4402 {
4403 HelpMarker("This demonstrate embedding a table into another table cell.");
4404
4405 if (ImGui::BeginTable("table_nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
4406 {
4407 ImGui::TableSetupColumn("A0");
4408 ImGui::TableSetupColumn("A1");
4409 ImGui::TableHeadersRow();
4410
4411 ImGui::TableNextColumn();
4412 ImGui::Text("A0 Row 0");
4413 {
4414 float rows_height = TEXT_BASE_HEIGHT * 2;
4415 if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
4416 {
4417 ImGui::TableSetupColumn("B0");
4418 ImGui::TableSetupColumn("B1");
4419 ImGui::TableHeadersRow();
4420
4421 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
4422 ImGui::TableNextColumn();
4423 ImGui::Text("B0 Row 0");
4424 ImGui::TableNextColumn();
4425 ImGui::Text("B1 Row 0");
4426 ImGui::TableNextRow(ImGuiTableRowFlags_None, rows_height);
4427 ImGui::TableNextColumn();
4428 ImGui::Text("B0 Row 1");
4429 ImGui::TableNextColumn();
4430 ImGui::Text("B1 Row 1");
4431
4432 ImGui::EndTable();
4433 }
4434 }
4435 ImGui::TableNextColumn(); ImGui::Text("A1 Row 0");
4436 ImGui::TableNextColumn(); ImGui::Text("A0 Row 1");
4437 ImGui::TableNextColumn(); ImGui::Text("A1 Row 1");
4438 ImGui::EndTable();
4439 }
4440 ImGui::TreePop();
4441 }
4442
4443 if (open_action != -1)
4444 ImGui::SetNextItemOpen(open_action != 0);
4445 if (ImGui::TreeNode("Row height"))
4446 {
4447 HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would requires a unique clipping rectangle per row.");
4448 if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV))
4449 {
4450 for (int row = 0; row < 10; row++)
4451 {
4452 float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
4453 ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
4454 ImGui::TableNextColumn();
4455 ImGui::Text("min_row_height = %.2f", min_row_height);
4456 }
4457 ImGui::EndTable();
4458 }
4459 ImGui::TreePop();
4460 }
4461
4462 if (open_action != -1)
4463 ImGui::SetNextItemOpen(open_action != 0);
4464 if (ImGui::TreeNode("Outer size"))
4465 {
4466 // Showcasing use of ImGuiTableFlags_NoHostExtendX and ImGuiTableFlags_NoHostExtendY
4467 // Important to that note how the two flags have slightly different behaviors!
4468 ImGui::Text("Using NoHostExtendX and NoHostExtendY:");
4469 PushStyleCompact();
4470 static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;
4471 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
4472 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
4473 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
4474 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
4475 PopStyleCompact();
4476
4477 ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 5.5f);
4478 if (ImGui::BeginTable("table1", 3, flags, outer_size))
4479 {
4480 for (int row = 0; row < 10; row++)
4481 {
4482 ImGui::TableNextRow();
4483 for (int column = 0; column < 3; column++)
4484 {
4485 ImGui::TableNextColumn();
4486 ImGui::Text("Cell %d,%d", column, row);
4487 }
4488 }
4489 ImGui::EndTable();
4490 }
4491 ImGui::SameLine();
4492 ImGui::Text("Hello!");
4493
4494 ImGui::Spacing();
4495
4496 ImGui::Text("Using explicit size:");
4497 if (ImGui::BeginTable("table2", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
4498 {
4499 for (int row = 0; row < 5; row++)
4500 {
4501 ImGui::TableNextRow();
4502 for (int column = 0; column < 3; column++)
4503 {
4504 ImGui::TableNextColumn();
4505 ImGui::Text("Cell %d,%d", column, row);
4506 }
4507 }
4508 ImGui::EndTable();
4509 }
4510 ImGui::SameLine();
4511 if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
4512 {
4513 for (int row = 0; row < 3; row++)
4514 {
4515 ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f);
4516 for (int column = 0; column < 3; column++)
4517 {
4518 ImGui::TableNextColumn();
4519 ImGui::Text("Cell %d,%d", column, row);
4520 }
4521 }
4522 ImGui::EndTable();
4523 }
4524
4525 ImGui::TreePop();
4526 }
4527
4528 if (open_action != -1)
4529 ImGui::SetNextItemOpen(open_action != 0);
4530 if (ImGui::TreeNode("Background color"))
4531 {
4532 static ImGuiTableFlags flags = ImGuiTableFlags_RowBg;
4533 static int row_bg_type = 1;
4534 static int row_bg_target = 1;
4535 static int cell_bg_type = 1;
4536
4537 PushStyleCompact();
4538 ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
4539 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
4540 ImGui::SameLine(); HelpMarker("ImGuiTableFlags_RowBg automatically sets RowBg0 to alternative colors pulled from the Style.");
4541 ImGui::Combo("row bg type", (int*)&row_bg_type, "None\0Red\0Gradient\0");
4542 ImGui::Combo("row bg target", (int*)&row_bg_target, "RowBg0\0RowBg1\0"); ImGui::SameLine(); HelpMarker("Target RowBg0 to override the alternating odd/even colors,\nTarget RowBg1 to blend with them.");
4543 ImGui::Combo("cell bg type", (int*)&cell_bg_type, "None\0Blue\0"); ImGui::SameLine(); HelpMarker("We are colorizing cells to B1->C2 here.");
4544 IM_ASSERT(row_bg_type >= 0 && row_bg_type <= 2);
4545 IM_ASSERT(row_bg_target >= 0 && row_bg_target <= 1);
4546 IM_ASSERT(cell_bg_type >= 0 && cell_bg_type <= 1);
4547 PopStyleCompact();
4548
4549 if (ImGui::BeginTable("table1", 5, flags))
4550 {
4551 for (int row = 0; row < 6; row++)
4552 {
4553 ImGui::TableNextRow();
4554
4555 // Demonstrate setting a row background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBgX, ...)'
4556 // We use a transparent color so we can see the one behind in case our target is RowBg1 and RowBg0 was already targeted by the ImGuiTableFlags_RowBg flag.
4557 if (row_bg_type != 0)
4558 {
4559 ImU32 row_bg_color = ImGui::GetColorU32(row_bg_type == 1 ? ImVec4(0.7f, 0.3f, 0.3f, 0.65f) : ImVec4(0.2f + row * 0.1f, 0.2f, 0.2f, 0.65f)); // Flat or Gradient?
4560 ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0 + row_bg_target, row_bg_color);
4561 }
4562
4563 // Fill cells
4564 for (int column = 0; column < 5; column++)
4565 {
4566 ImGui::TableSetColumnIndex(column);
4567 ImGui::Text("%c%c", 'A' + row, '0' + column);
4568
4569 // Change background of Cells B1->C2
4570 // Demonstrate setting a cell background color with 'ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ...)'
4571 // (the CellBg color will be blended over the RowBg and ColumnBg colors)
4572 // We can also pass a column number as a third parameter to TableSetBgColor() and do this outside the column loop.
4573 if (row >= 1 && row <= 2 && column >= 1 && column <= 2 && cell_bg_type == 1)
4574 {
4575 ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 0.65f));
4576 ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
4577 }
4578 }
4579 }
4580 ImGui::EndTable();
4581 }
4582 ImGui::TreePop();
4583 }
4584
4585 if (open_action != -1)
4586 ImGui::SetNextItemOpen(open_action != 0);
4587 if (ImGui::TreeNode("Tree view"))
4588 {
4589 static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
4590
4591 if (ImGui::BeginTable("3ways", 3, flags))
4592 {
4593 // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
4594 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide);
4595 ImGui::TableSetupColumn("Size", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
4596 ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 18.0f);
4597 ImGui::TableHeadersRow();
4598
4599 // Simple storage to output a dummy file-system.
4600 struct MyTreeNode
4601 {
4602 const char* Name;
4603 const char* Type;
4604 int Size;
4605 int ChildIdx;
4606 int ChildCount;
4607 static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
4608 {
4609 ImGui::TableNextRow();
4610 ImGui::TableNextColumn();
4611 const bool is_folder = (node->ChildCount > 0);
4612 if (is_folder)
4613 {
4614 bool open = ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_SpanFullWidth);
4615 ImGui::TableNextColumn();
4616 ImGui::TextDisabled("--");
4617 ImGui::TableNextColumn();
4618 ImGui::TextUnformatted(node->Type);
4619 if (open)
4620 {
4621 for (int child_n = 0; child_n < node->ChildCount; child_n++)
4622 DisplayNode(&all_nodes[node->ChildIdx + child_n], all_nodes);
4623 ImGui::TreePop();
4624 }
4625 }
4626 else
4627 {
4628 ImGui::TreeNodeEx(node->Name, ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
4629 ImGui::TableNextColumn();
4630 ImGui::Text("%d", node->Size);
4631 ImGui::TableNextColumn();
4632 ImGui::TextUnformatted(node->Type);
4633 }
4634 }
4635 };
4636 static const MyTreeNode nodes[] =
4637 {
4638 { "Root", "Folder", -1, 1, 3 }, // 0
4639 { "Music", "Folder", -1, 4, 2 }, // 1
4640 { "Textures", "Folder", -1, 6, 3 }, // 2
4641 { "desktop.ini", "System file", 1024, -1,-1 }, // 3
4642 { "File1_a.wav", "Audio file", 123000, -1,-1 }, // 4
4643 { "File1_b.wav", "Audio file", 456000, -1,-1 }, // 5
4644 { "Image001.png", "Image file", 203128, -1,-1 }, // 6
4645 { "Copy of Image001.png", "Image file", 203256, -1,-1 }, // 7
4646 { "Copy of Image001 (Final2).png","Image file", 203512, -1,-1 }, // 8
4647 };
4648
4649 MyTreeNode::DisplayNode(&nodes[0], nodes);
4650
4651 ImGui::EndTable();
4652 }
4653 ImGui::TreePop();
4654 }
4655
4656 if (open_action != -1)
4657 ImGui::SetNextItemOpen(open_action != 0);
4658 if (ImGui::TreeNode("Item width"))
4659 {
4660 HelpMarker(
4661 "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
4662 "Note that on auto-resizing non-resizable fixed columns, querying the content width for e.g. right-alignment doesn't make sense.");
4663 if (ImGui::BeginTable("table_item_width", 3, ImGuiTableFlags_Borders))
4664 {
4665 ImGui::TableSetupColumn("small");
4666 ImGui::TableSetupColumn("half");
4667 ImGui::TableSetupColumn("right-align");
4668 ImGui::TableHeadersRow();
4669
4670 for (int row = 0; row < 3; row++)
4671 {
4672 ImGui::TableNextRow();
4673 if (row == 0)
4674 {
4675 // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
4676 ImGui::TableSetColumnIndex(0);
4677 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
4678 ImGui::TableSetColumnIndex(1);
4679 ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
4680 ImGui::TableSetColumnIndex(2);
4681 ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
4682 }
4683
4684 // Draw our contents
4685 static float dummy_f = 0.0f;
4686 ImGui::PushID(row);
4687 ImGui::TableSetColumnIndex(0);
4688 ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
4689 ImGui::TableSetColumnIndex(1);
4690 ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
4691 ImGui::TableSetColumnIndex(2);
4692 ImGui::SliderFloat("float2", &dummy_f, 0.0f, 1.0f);
4693 ImGui::PopID();
4694 }
4695 ImGui::EndTable();
4696 }
4697 ImGui::TreePop();
4698 }
4699
4700 // Demonstrate using TableHeader() calls instead of TableHeadersRow()
4701 if (open_action != -1)
4702 ImGui::SetNextItemOpen(open_action != 0);
4703 if (ImGui::TreeNode("Custom headers"))
4704 {
4705 const int COLUMNS_COUNT = 3;
4706 if (ImGui::BeginTable("table_custom_headers", COLUMNS_COUNT, ImGuiTableFlags_Borders | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
4707 {
4708 ImGui::TableSetupColumn("Apricot");
4709 ImGui::TableSetupColumn("Banana");
4710 ImGui::TableSetupColumn("Cherry");
4711
4712 // Dummy entire-column selection storage
4713 // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
4714 static bool column_selected[3] = {};
4715
4716 // Instead of calling TableHeadersRow() we'll submit custom headers ourselves
4717 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
4718 for (int column = 0; column < COLUMNS_COUNT; column++)
4719 {
4720 ImGui::TableSetColumnIndex(column);
4721 const char* column_name = ImGui::TableGetColumnName(column); // Retrieve name passed to TableSetupColumn()
4722 ImGui::PushID(column);
4723 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
4724 ImGui::Checkbox("##checkall", &column_selected[column]);
4725 ImGui::PopStyleVar();
4726 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
4727 ImGui::TableHeader(column_name);
4728 ImGui::PopID();
4729 }
4730
4731 for (int row = 0; row < 5; row++)
4732 {
4733 ImGui::TableNextRow();
4734 for (int column = 0; column < 3; column++)
4735 {
4736 char buf[32];
4737 sprintf(buf, "Cell %d,%d", column, row);
4738 ImGui::TableSetColumnIndex(column);
4739 ImGui::Selectable(buf, column_selected[column]);
4740 }
4741 }
4742 ImGui::EndTable();
4743 }
4744 ImGui::TreePop();
4745 }
4746
4747 // Demonstrate creating custom context menus inside columns, while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
4748 if (open_action != -1)
4749 ImGui::SetNextItemOpen(open_action != 0);
4750 if (ImGui::TreeNode("Context menus"))
4751 {
4752 HelpMarker("By default, right-clicking over a TableHeadersRow()/TableHeader() line will open the default context-menu.\nUsing ImGuiTableFlags_ContextMenuInBody we also allow right-clicking over columns body.");
4753 static ImGuiTableFlags flags1 = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ContextMenuInBody;
4754
4755 PushStyleCompact();
4756 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags1, ImGuiTableFlags_ContextMenuInBody);
4757 PopStyleCompact();
4758
4759 // Context Menus: first example
4760 // [1.1] Right-click on the TableHeadersRow() line to open the default table context menu.
4761 // [1.2] Right-click in columns also open the default table context menu (if ImGuiTableFlags_ContextMenuInBody is set)
4762 const int COLUMNS_COUNT = 3;
4763 if (ImGui::BeginTable("table_context_menu", COLUMNS_COUNT, flags1))
4764 {
4765 ImGui::TableSetupColumn("One");
4766 ImGui::TableSetupColumn("Two");
4767 ImGui::TableSetupColumn("Three");
4768
4769 // [1.1]] Right-click on the TableHeadersRow() line to open the default table context menu.
4770 ImGui::TableHeadersRow();
4771
4772 // Submit dummy contents
4773 for (int row = 0; row < 4; row++)
4774 {
4775 ImGui::TableNextRow();
4776 for (int column = 0; column < COLUMNS_COUNT; column++)
4777 {
4778 ImGui::TableSetColumnIndex(column);
4779 ImGui::Text("Cell %d,%d", column, row);
4780 }
4781 }
4782 ImGui::EndTable();
4783 }
4784
4785 // Context Menus: second example
4786 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
4787 // [2.2] Right-click on the ".." to open a custom popup
4788 // [2.3] Right-click in columns to open another custom popup
4789 HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) and custom per-colum context menu (over column body).");
4790 ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
4791 if (ImGui::BeginTable("table_context_menu_2", COLUMNS_COUNT, flags2))
4792 {
4793 ImGui::TableSetupColumn("One");
4794 ImGui::TableSetupColumn("Two");
4795 ImGui::TableSetupColumn("Three");
4796
4797 // [2.1] Right-click on the TableHeadersRow() line to open the default table context menu.
4798 ImGui::TableHeadersRow();
4799 for (int row = 0; row < 4; row++)
4800 {
4801 ImGui::TableNextRow();
4802 for (int column = 0; column < COLUMNS_COUNT; column++)
4803 {
4804 // Submit dummy contents
4805 ImGui::TableSetColumnIndex(column);
4806 ImGui::Text("Cell %d,%d", column, row);
4807 ImGui::SameLine();
4808
4809 // [2.2] Right-click on the ".." to open a custom popup
4810 ImGui::PushID(row * COLUMNS_COUNT + column);
4811 ImGui::SmallButton("..");
4812 if (ImGui::BeginPopupContextItem())
4813 {
4814 ImGui::Text("This is the popup for Button(\"..\") in Cell %d,%d", column, row);
4815 if (ImGui::Button("Close"))
4816 ImGui::CloseCurrentPopup();
4817 ImGui::EndPopup();
4818 }
4819 ImGui::PopID();
4820 }
4821 }
4822
4823 // [2.3] Right-click anywhere in columns to open another custom popup
4824 // (instead of testing for !IsAnyItemHovered() we could also call OpenPopup() with ImGuiPopupFlags_NoOpenOverExistingPopup
4825 // to manage popup priority as the popups triggers, here "are we hovering a column" are overlapping)
4826 int hovered_column = -1;
4827 for (int column = 0; column < COLUMNS_COUNT + 1; column++)
4828 {
4829 ImGui::PushID(column);
4830 if (ImGui::TableGetColumnFlags(column) & ImGuiTableColumnFlags_IsHovered)
4831 hovered_column = column;
4832 if (hovered_column == column && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(1))
4833 ImGui::OpenPopup("MyPopup");
4834 if (ImGui::BeginPopup("MyPopup"))
4835 {
4836 if (column == COLUMNS_COUNT)
4837 ImGui::Text("This is a custom popup for unused space after the last column.");
4838 else
4839 ImGui::Text("This is a custom popup for Column %d", column);
4840 if (ImGui::Button("Close"))
4841 ImGui::CloseCurrentPopup();
4842 ImGui::EndPopup();
4843 }
4844 ImGui::PopID();
4845 }
4846
4847 ImGui::EndTable();
4848 ImGui::Text("Hovered column: %d", hovered_column);
4849 }
4850 ImGui::TreePop();
4851 }
4852
4853 // Demonstrate creating multiple tables with the same ID
4854 if (open_action != -1)
4855 ImGui::SetNextItemOpen(open_action != 0);
4856 if (ImGui::TreeNode("Synced instances"))
4857 {
4858 HelpMarker("Multiple tables with the same identifier will share their settings, width, visibility, order etc.");
4859 for (int n = 0; n < 3; n++)
4860 {
4861 char buf[32];
4862 sprintf(buf, "Synced Table %d", n);
4863 bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
4864 if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings))
4865 {
4866 ImGui::TableSetupColumn("One");
4867 ImGui::TableSetupColumn("Two");
4868 ImGui::TableSetupColumn("Three");
4869 ImGui::TableHeadersRow();
4870 for (int cell = 0; cell < 9; cell++)
4871 {
4872 ImGui::TableNextColumn();
4873 ImGui::Text("this cell %d", cell);
4874 }
4875 ImGui::EndTable();
4876 }
4877 }
4878 ImGui::TreePop();
4879 }
4880
4881 // Demonstrate using Sorting facilities
4882 // This is a simplified version of the "Advanced" example, where we mostly focus on the code necessary to handle sorting.
4883 // Note that the "Advanced" example also showcase manually triggering a sort (e.g. if item quantities have been modified)
4884 static const char* template_items_names[] =
4885 {
4886 "Banana", "Apple", "Cherry", "Watermelon", "Grapefruit", "Strawberry", "Mango",
4887 "Kiwi", "Orange", "Pineapple", "Blueberry", "Plum", "Coconut", "Pear", "Apricot"
4888 };
4889 if (open_action != -1)
4890 ImGui::SetNextItemOpen(open_action != 0);
4891 if (ImGui::TreeNode("Sorting"))
4892 {
4893 // Create item list
4894 static ImVector<MyItem> items;
4895 if (items.Size == 0)
4896 {
4897 items.resize(50, MyItem());
4898 for (int n = 0; n < items.Size; n++)
4899 {
4900 const int template_n = n % IM_ARRAYSIZE(template_items_names);
4901 MyItem& item = items[n];
4902 item.ID = n;
4903 item.Name = template_items_names[template_n];
4904 item.Quantity = (n * n - n) % 20; // Assign default quantities
4905 }
4906 }
4907
4908 // Options
4909 static ImGuiTableFlags flags =
4910 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
4911 | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
4912 | ImGuiTableFlags_ScrollY;
4913 PushStyleCompact();
4914 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
4915 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
4916 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
4917 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
4918 PopStyleCompact();
4919
4920 if (ImGui::BeginTable("table_sorting", 4, flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 15), 0.0f))
4921 {
4922 // Declare columns
4923 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
4924 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
4925 // Demonstrate using a mixture of flags among available sort-related flags:
4926 // - ImGuiTableColumnFlags_DefaultSort
4927 // - ImGuiTableColumnFlags_NoSort / ImGuiTableColumnFlags_NoSortAscending / ImGuiTableColumnFlags_NoSortDescending
4928 // - ImGuiTableColumnFlags_PreferSortAscending / ImGuiTableColumnFlags_PreferSortDescending
4929 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_ID);
4930 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
4931 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
4932 ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Quantity);
4933 ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
4934 ImGui::TableHeadersRow();
4935
4936 // Sort our data if sort specs have been changed!
4937 if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs())
4938 if (sorts_specs->SpecsDirty)
4939 {
4940 MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function.
4941 if (items.Size > 1)
4942 qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs);
4943 MyItem::s_current_sort_specs = NULL;
4944 sorts_specs->SpecsDirty = false;
4945 }
4946
4947 // Demonstrate using clipper for large vertical lists
4948 ImGuiListClipper clipper;
4949 clipper.Begin(items.Size);
4950 while (clipper.Step())
4951 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
4952 {
4953 // Display a data item
4954 MyItem* item = &items[row_n];
4955 ImGui::PushID(item->ID);
4956 ImGui::TableNextRow();
4957 ImGui::TableNextColumn();
4958 ImGui::Text("%04d", item->ID);
4959 ImGui::TableNextColumn();
4960 ImGui::TextUnformatted(item->Name);
4961 ImGui::TableNextColumn();
4962 ImGui::SmallButton("None");
4963 ImGui::TableNextColumn();
4964 ImGui::Text("%d", item->Quantity);
4965 ImGui::PopID();
4966 }
4967 ImGui::EndTable();
4968 }
4969 ImGui::TreePop();
4970 }
4971
4972 // In this example we'll expose most table flags and settings.
4973 // For specific flags and settings refer to the corresponding section for more detailed explanation.
4974 // This section is mostly useful to experiment with combining certain flags or settings with each others.
4975 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // [DEBUG]
4976 if (open_action != -1)
4977 ImGui::SetNextItemOpen(open_action != 0);
4978 if (ImGui::TreeNode("Advanced"))
4979 {
4980 static ImGuiTableFlags flags =
4981 ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
4982 | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
4983 | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
4984 | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
4985 | ImGuiTableFlags_SizingFixedFit;
4986
4987 enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
4988 static int contents_type = CT_SelectableSpanRow;
4989 const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
4990 static int freeze_cols = 1;
4991 static int freeze_rows = 1;
4992 static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
4993 static ImVec2 outer_size_value = ImVec2(0.0f, TEXT_BASE_HEIGHT * 12);
4994 static float row_min_height = 0.0f; // Auto
4995 static float inner_width_with_scroll = 0.0f; // Auto-extend
4996 static bool outer_size_enabled = true;
4997 static bool show_headers = true;
4998 static bool show_wrapped_text = false;
4999 //static ImGuiTextFilter filter;
5000 //ImGui::SetNextItemOpen(true, ImGuiCond_Once); // FIXME-TABLE: Enabling this results in initial clipped first pass on table which tend to affects column sizing
5001 if (ImGui::TreeNode("Options"))
5002 {
5003 // Make the UI compact because there are so many fields
5004 PushStyleCompact();
5005 ImGui::PushItemWidth(TEXT_BASE_WIDTH * 28.0f);
5006
5007 if (ImGui::TreeNodeEx("Features:", ImGuiTreeNodeFlags_DefaultOpen))
5008 {
5009 ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
5010 ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
5011 ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
5012 ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
5013 ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
5014 ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
5015 ImGui::TreePop();
5016 }
5017
5018 if (ImGui::TreeNodeEx("Decorations:", ImGuiTreeNodeFlags_DefaultOpen))
5019 {
5020 ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
5021 ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
5022 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
5023 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
5024 ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
5025 ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
5026 ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
5027 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers");
5028 ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBodyUntilResize", &flags, ImGuiTableFlags_NoBordersInBodyUntilResize); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers)");
5029 ImGui::TreePop();
5030 }
5031
5032 if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
5033 {
5034 EditTableSizingFlags(&flags);
5035 ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
5036 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendX", &flags, ImGuiTableFlags_NoHostExtendX);
5037 ImGui::SameLine(); HelpMarker("Make outer width auto-fit to columns, overriding outer_size.x value.\n\nOnly available when ScrollX/ScrollY are disabled and Stretch columns are not used.");
5038 ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
5039 ImGui::SameLine(); HelpMarker("Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit).\n\nOnly available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.");
5040 ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
5041 ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
5042 ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
5043 ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
5044 ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
5045 ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.");
5046 ImGui::TreePop();
5047 }
5048
5049 if (ImGui::TreeNodeEx("Padding:", ImGuiTreeNodeFlags_DefaultOpen))
5050 {
5051 ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
5052 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
5053 ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
5054 ImGui::TreePop();
5055 }
5056
5057 if (ImGui::TreeNodeEx("Scrolling:", ImGuiTreeNodeFlags_DefaultOpen))
5058 {
5059 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
5060 ImGui::SameLine();
5061 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5062 ImGui::DragInt("freeze_cols", &freeze_cols, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5063 ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
5064 ImGui::SameLine();
5065 ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
5066 ImGui::DragInt("freeze_rows", &freeze_rows, 0.2f, 0, 9, NULL, ImGuiSliderFlags_NoInput);
5067 ImGui::TreePop();
5068 }
5069
5070 if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
5071 {
5072 ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
5073 ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
5074 ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
5075 ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
5076 ImGui::TreePop();
5077 }
5078
5079 if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
5080 {
5081 ImGui::Checkbox("show_headers", &show_headers);
5082 ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
5083
5084 ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
5085 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
5086 ImGui::Checkbox("outer_size", &outer_size_enabled);
5087 ImGui::SameLine();
5088 HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
5089 "- The table is output directly in the parent window.\n"
5090 "- OuterSize.x < 0.0f will right-align the table.\n"
5091 "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch column.\n"
5092 "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
5093
5094 // From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
5095 // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
5096 ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
5097
5098 ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
5099 ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
5100
5101 ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
5102 ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
5103 //filter.Draw("filter");
5104 ImGui::TreePop();
5105 }
5106
5107 ImGui::PopItemWidth();
5108 PopStyleCompact();
5109 ImGui::Spacing();
5110 ImGui::TreePop();
5111 }
5112
5113 // Update item list if we changed the number of items
5114 static ImVector<MyItem> items;
5115 static ImVector<int> selection;
5116 static bool items_need_sort = false;
5117 if (items.Size != items_count)
5118 {
5119 items.resize(items_count, MyItem());
5120 for (int n = 0; n < items_count; n++)
5121 {
5122 const int template_n = n % IM_ARRAYSIZE(template_items_names);
5123 MyItem& item = items[n];
5124 item.ID = n;
5125 item.Name = template_items_names[template_n];
5126 item.Quantity = (template_n == 3) ? 10 : (template_n == 4) ? 20 : 0; // Assign default quantities
5127 }
5128 }
5129
5130 const ImDrawList* parent_draw_list = ImGui::GetWindowDrawList();
5131 const int parent_draw_list_draw_cmd_count = parent_draw_list->CmdBuffer.Size;
5132 ImVec2 table_scroll_cur, table_scroll_max; // For debug display
5133 const ImDrawList* table_draw_list = NULL; // "
5134
5135 // Submit table
5136 const float inner_width_to_use = (flags & ImGuiTableFlags_ScrollX) ? inner_width_with_scroll : 0.0f;
5137 if (ImGui::BeginTable("table_advanced", 6, flags, outer_size_enabled ? outer_size_value : ImVec2(0, 0), inner_width_to_use))
5138 {
5139 // Declare columns
5140 // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
5141 // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
5142 ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
5143 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
5144 ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
5145 ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
5146 ImGui::TableSetupColumn("Description", (flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Description);
5147 ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
5148 ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
5149
5150 // Sort our data if sort specs have been changed!
5151 ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs();
5152 if (sorts_specs && sorts_specs->SpecsDirty)
5153 items_need_sort = true;
5154 if (sorts_specs && items_need_sort && items.Size > 1)
5155 {
5156 MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function.
5157 qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs);
5158 MyItem::s_current_sort_specs = NULL;
5159 sorts_specs->SpecsDirty = false;
5160 }
5161 items_need_sort = false;
5162
5163 // Take note of whether we are currently sorting based on the Quantity field,
5164 // we will use this to trigger sorting when we know the data of this column has been modified.
5165 const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;
5166
5167 // Show headers
5168 if (show_headers)
5169 ImGui::TableHeadersRow();
5170
5171 // Show data
5172 // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
5173 ImGui::PushButtonRepeat(true);
5174 #if 1
5175 // Demonstrate using clipper for large vertical lists
5176 ImGuiListClipper clipper;
5177 clipper.Begin(items.Size);
5178 while (clipper.Step())
5179 {
5180 for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
5181 #else
5182 // Without clipper
5183 {
5184 for (int row_n = 0; row_n < items.Size; row_n++)
5185 #endif
5186 {
5187 MyItem* item = &items[row_n];
5188 //if (!filter.PassFilter(item->Name))
5189 // continue;
5190
5191 const bool item_is_selected = selection.contains(item->ID);
5192 ImGui::PushID(item->ID);
5193 ImGui::TableNextRow(ImGuiTableRowFlags_None, row_min_height);
5194
5195 // For the demo purpose we can select among different type of items submitted in the first column
5196 ImGui::TableSetColumnIndex(0);
5197 char label[32];
5198 sprintf(label, "%04d", item->ID);
5199 if (contents_type == CT_Text)
5200 ImGui::TextUnformatted(label);
5201 else if (contents_type == CT_Button)
5202 ImGui::Button(label);
5203 else if (contents_type == CT_SmallButton)
5204 ImGui::SmallButton(label);
5205 else if (contents_type == CT_FillButton)
5206 ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f));
5207 else if (contents_type == CT_Selectable || contents_type == CT_SelectableSpanRow)
5208 {
5209 ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap : ImGuiSelectableFlags_None;
5210 if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))
5211 {
5212 if (ImGui::GetIO().KeyCtrl)
5213 {
5214 if (item_is_selected)
5215 selection.find_erase_unsorted(item->ID);
5216 else
5217 selection.push_back(item->ID);
5218 }
5219 else
5220 {
5221 selection.clear();
5222 selection.push_back(item->ID);
5223 }
5224 }
5225 }
5226
5227 if (ImGui::TableSetColumnIndex(1))
5228 ImGui::TextUnformatted(item->Name);
5229
5230 // Here we demonstrate marking our data set as needing to be sorted again if we modified a quantity,
5231 // and we are currently sorting on the column showing the Quantity.
5232 // To avoid triggering a sort while holding the button, we only trigger it when the button has been released.
5233 // You will probably need a more advanced system in your code if you want to automatically sort when a specific entry changes.
5234 if (ImGui::TableSetColumnIndex(2))
5235 {
5236 if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
5237 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
5238 ImGui::SameLine();
5239 if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
5240 if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
5241 }
5242
5243 if (ImGui::TableSetColumnIndex(3))
5244 ImGui::Text("%d", item->Quantity);
5245
5246 ImGui::TableSetColumnIndex(4);
5247 if (show_wrapped_text)
5248 ImGui::TextWrapped("Lorem ipsum dolor sit amet");
5249 else
5250 ImGui::Text("Lorem ipsum dolor sit amet");
5251
5252 if (ImGui::TableSetColumnIndex(5))
5253 ImGui::Text("1234");
5254
5255 ImGui::PopID();
5256 }
5257 }
5258 ImGui::PopButtonRepeat();
5259
5260 // Store some info to display debug details below
5261 table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
5262 table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
5263 table_draw_list = ImGui::GetWindowDrawList();
5264 ImGui::EndTable();
5265 }
5266 static bool show_debug_details = false;
5267 ImGui::Checkbox("Debug details", &show_debug_details);
5268 if (show_debug_details && table_draw_list)
5269 {
5270 ImGui::SameLine(0.0f, 0.0f);
5271 const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
5272 if (table_draw_list == parent_draw_list)
5273 ImGui::Text(": DrawCmd: +%d (in same window)",
5274 table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
5275 else
5276 ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
5277 table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
5278 }
5279 ImGui::TreePop();
5280 }
5281
5282 ImGui::PopID();
5283
5284 ShowDemoWindowColumns();
5285
5286 if (disable_indent)
5287 ImGui::PopStyleVar();
5288 }
5289
5290 // Demonstrate old/legacy Columns API!
5291 // [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!]
5292 static void ShowDemoWindowColumns()
5293 {
5294 bool open = ImGui::TreeNode("Legacy Columns API");
5295 ImGui::SameLine();
5296 HelpMarker("Columns() is an old API! Prefer using the more flexible and powerful BeginTable() API!");
5297 if (!open)
5298 return;
5299
5300 // Basic columns
5301 if (ImGui::TreeNode("Basic"))
5302 {
5303 ImGui::Text("Without border:");
5304 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
5305 ImGui::Separator();
5306 for (int n = 0; n < 14; n++)
5307 {
5308 char label[32];
5309 sprintf(label, "Item %d", n);
5310 if (ImGui::Selectable(label)) {}
5311 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
5312 ImGui::NextColumn();
5313 }
5314 ImGui::Columns(1);
5315 ImGui::Separator();
5316
5317 ImGui::Text("With border:");
5318 ImGui::Columns(4, "mycolumns"); // 4-ways, with border
5319 ImGui::Separator();
5320 ImGui::Text("ID"); ImGui::NextColumn();
5321 ImGui::Text("Name"); ImGui::NextColumn();
5322 ImGui::Text("Path"); ImGui::NextColumn();
5323 ImGui::Text("Hovered"); ImGui::NextColumn();
5324 ImGui::Separator();
5325 const char* names[3] = { "One", "Two", "Three" };
5326 const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
5327 static int selected = -1;
5328 for (int i = 0; i < 3; i++)
5329 {
5330 char label[32];
5331 sprintf(label, "%04d", i);
5332 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
5333 selected = i;
5334 bool hovered = ImGui::IsItemHovered();
5335 ImGui::NextColumn();
5336 ImGui::Text(names[i]); ImGui::NextColumn();
5337 ImGui::Text(paths[i]); ImGui::NextColumn();
5338 ImGui::Text("%d", hovered); ImGui::NextColumn();
5339 }
5340 ImGui::Columns(1);
5341 ImGui::Separator();
5342 ImGui::TreePop();
5343 }
5344
5345 if (ImGui::TreeNode("Borders"))
5346 {
5347 // NB: Future columns API should allow automatic horizontal borders.
5348 static bool h_borders = true;
5349 static bool v_borders = true;
5350 static int columns_count = 4;
5351 const int lines_count = 3;
5352 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
5353 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
5354 if (columns_count < 2)
5355 columns_count = 2;
5356 ImGui::SameLine();
5357 ImGui::Checkbox("horizontal", &h_borders);
5358 ImGui::SameLine();
5359 ImGui::Checkbox("vertical", &v_borders);
5360 ImGui::Columns(columns_count, NULL, v_borders);
5361 for (int i = 0; i < columns_count * lines_count; i++)
5362 {
5363 if (h_borders && ImGui::GetColumnIndex() == 0)
5364 ImGui::Separator();
5365 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
5366 ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
5367 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
5368 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
5369 ImGui::Text("Long text that is likely to clip");
5370 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
5371 ImGui::NextColumn();
5372 }
5373 ImGui::Columns(1);
5374 if (h_borders)
5375 ImGui::Separator();
5376 ImGui::TreePop();
5377 }
5378
5379 // Create multiple items in a same cell before switching to next column
5380 if (ImGui::TreeNode("Mixed items"))
5381 {
5382 ImGui::Columns(3, "mixed");
5383 ImGui::Separator();
5384
5385 ImGui::Text("Hello");
5386 ImGui::Button("Banana");
5387 ImGui::NextColumn();
5388
5389 ImGui::Text("ImGui");
5390 ImGui::Button("Apple");
5391 static float foo = 1.0f;
5392 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
5393 ImGui::Text("An extra line here.");
5394 ImGui::NextColumn();
5395
5396 ImGui::Text("Sailor");
5397 ImGui::Button("Corniflower");
5398 static float bar = 1.0f;
5399 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
5400 ImGui::NextColumn();
5401
5402 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
5403 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
5404 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
5405 ImGui::Columns(1);
5406 ImGui::Separator();
5407 ImGui::TreePop();
5408 }
5409
5410 // Word wrapping
5411 if (ImGui::TreeNode("Word-wrapping"))
5412 {
5413 ImGui::Columns(2, "word-wrapping");
5414 ImGui::Separator();
5415 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
5416 ImGui::TextWrapped("Hello Left");
5417 ImGui::NextColumn();
5418 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
5419 ImGui::TextWrapped("Hello Right");
5420 ImGui::Columns(1);
5421 ImGui::Separator();
5422 ImGui::TreePop();
5423 }
5424
5425 if (ImGui::TreeNode("Horizontal Scrolling"))
5426 {
5427 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
5428 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
5429 ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar);
5430 ImGui::Columns(10);
5431
5432 // Also demonstrate using clipper for large vertical lists
5433 int ITEMS_COUNT = 2000;
5434 ImGuiListClipper clipper;
5435 clipper.Begin(ITEMS_COUNT);
5436 while (clipper.Step())
5437 {
5438 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
5439 for (int j = 0; j < 10; j++)
5440 {
5441 ImGui::Text("Line %d Column %d...", i, j);
5442 ImGui::NextColumn();
5443 }
5444 }
5445 ImGui::Columns(1);
5446 ImGui::EndChild();
5447 ImGui::TreePop();
5448 }
5449
5450 if (ImGui::TreeNode("Tree"))
5451 {
5452 ImGui::Columns(2, "tree", true);
5453 for (int x = 0; x < 3; x++)
5454 {
5455 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
5456 ImGui::NextColumn();
5457 ImGui::Text("Node contents");
5458 ImGui::NextColumn();
5459 if (open1)
5460 {
5461 for (int y = 0; y < 3; y++)
5462 {
5463 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
5464 ImGui::NextColumn();
5465 ImGui::Text("Node contents");
5466 if (open2)
5467 {
5468 ImGui::Text("Even more contents");
5469 if (ImGui::TreeNode("Tree in column"))
5470 {
5471 ImGui::Text("The quick brown fox jumps over the lazy dog");
5472 ImGui::TreePop();
5473 }
5474 }
5475 ImGui::NextColumn();
5476 if (open2)
5477 ImGui::TreePop();
5478 }
5479 ImGui::TreePop();
5480 }
5481 }
5482 ImGui::Columns(1);
5483 ImGui::TreePop();
5484 }
5485
5486 ImGui::TreePop();
5487 }
5488
5489 static void ShowDemoWindowMisc()
5490 {
5491 if (ImGui::CollapsingHeader("Filtering"))
5492 {
5493 // Helper class to easy setup a text filter.
5494 // You may want to implement a more feature-full filtering scheme in your own application.
5495 static ImGuiTextFilter filter;
5496 ImGui::Text("Filter usage:\n"
5497 " \"\" display all lines\n"
5498 " \"xxx\" display lines containing \"xxx\"\n"
5499 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
5500 " \"-xxx\" hide lines containing \"xxx\"");
5501 filter.Draw();
5502 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
5503 for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
5504 if (filter.PassFilter(lines[i]))
5505 ImGui::BulletText("%s", lines[i]);
5506 }
5507
5508 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus"))
5509 {
5510 ImGuiIO& io = ImGui::GetIO();
5511
5512 // Display ImGuiIO output flags
5513 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
5514 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
5515 ImGui::Text("WantTextInput: %d", io.WantTextInput);
5516 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos);
5517 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible);
5518
5519 // Display Mouse state
5520 if (ImGui::TreeNode("Mouse State"))
5521 {
5522 if (ImGui::IsMousePosValid())
5523 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
5524 else
5525 ImGui::Text("Mouse pos: <INVALID>");
5526 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
5527 ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
5528 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); }
5529 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); }
5530 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); }
5531 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
5532 ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused
5533 ImGui::TreePop();
5534 }
5535
5536 // Display Keyboard/Mouse state
5537 if (ImGui::TreeNode("Keyboard & Navigation State"))
5538 {
5539 ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyDown(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); }
5540 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); }
5541 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); }
5542 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
5543 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.
5544
5545 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 (%.02f secs)", i, io.NavInputs[i], io.NavInputsDownDuration[i]); }
5546 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); }
5547
5548 ImGui::Button("Hovering me sets the\nkeyboard capture flag");
5549 if (ImGui::IsItemHovered())
5550 ImGui::CaptureKeyboardFromApp(true);
5551 ImGui::SameLine();
5552 ImGui::Button("Holding me clears the\nthe keyboard capture flag");
5553 if (ImGui::IsItemActive())
5554 ImGui::CaptureKeyboardFromApp(false);
5555 ImGui::TreePop();
5556 }
5557
5558 if (ImGui::TreeNode("Tabbing"))
5559 {
5560 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
5561 static char buf[32] = "hello";
5562 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
5563 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
5564 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
5565 ImGui::PushAllowKeyboardFocus(false);
5566 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
5567 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
5568 ImGui::PopAllowKeyboardFocus();
5569 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
5570 ImGui::TreePop();
5571 }
5572
5573 if (ImGui::TreeNode("Focus from code"))
5574 {
5575 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
5576 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
5577 bool focus_3 = ImGui::Button("Focus on 3");
5578 int has_focus = 0;
5579 static char buf[128] = "click on a button to set focus";
5580
5581 if (focus_1) ImGui::SetKeyboardFocusHere();
5582 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
5583 if (ImGui::IsItemActive()) has_focus = 1;
5584
5585 if (focus_2) ImGui::SetKeyboardFocusHere();
5586 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
5587 if (ImGui::IsItemActive()) has_focus = 2;
5588
5589 ImGui::PushAllowKeyboardFocus(false);
5590 if (focus_3) ImGui::SetKeyboardFocusHere();
5591 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
5592 if (ImGui::IsItemActive()) has_focus = 3;
5593 ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
5594 ImGui::PopAllowKeyboardFocus();
5595
5596 if (has_focus)
5597 ImGui::Text("Item with focus: %d", has_focus);
5598 else
5599 ImGui::Text("Item with focus: <none>");
5600
5601 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
5602 static float f3[3] = { 0.0f, 0.0f, 0.0f };
5603 int focus_ahead = -1;
5604 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
5605 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
5606 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
5607 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
5608 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
5609
5610 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
5611 ImGui::TreePop();
5612 }
5613
5614 if (ImGui::TreeNode("Dragging"))
5615 {
5616 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
5617 for (int button = 0; button < 3; button++)
5618 {
5619 ImGui::Text("IsMouseDragging(%d):", button);
5620 ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button));
5621 ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
5622 ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
5623 }
5624
5625 ImGui::Button("Drag Me");
5626 if (ImGui::IsItemActive())
5627 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
5628
5629 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
5630 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
5631 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
5632 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
5633 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
5634 ImVec2 mouse_delta = io.MouseDelta;
5635 ImGui::Text("GetMouseDragDelta(0):");
5636 ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
5637 ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
5638 ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
5639 ImGui::TreePop();
5640 }
5641
5642 if (ImGui::TreeNode("Mouse cursors"))
5643 {
5644 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
5645 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
5646
5647 ImGuiMouseCursor current = ImGui::GetMouseCursor();
5648 ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
5649 ImGui::Text("Hover to see mouse cursors:");
5650 ImGui::SameLine(); HelpMarker(
5651 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
5652 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
5653 "otherwise your backend needs to handle it.");
5654 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
5655 {
5656 char label[32];
5657 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
5658 ImGui::Bullet(); ImGui::Selectable(label, false);
5659 if (ImGui::IsItemHovered())
5660 ImGui::SetMouseCursor(i);
5661 }
5662 ImGui::TreePop();
5663 }
5664 }
5665 }
5666
5667 //-----------------------------------------------------------------------------
5668 // [SECTION] About Window / ShowAboutWindow()
5669 // Access from Dear ImGui Demo -> Tools -> About
5670 //-----------------------------------------------------------------------------
5671
5672 void ImGui::ShowAboutWindow(bool* p_open)
5673 {
5674 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
5675 {
5676 ImGui::End();
5677 return;
5678 }
5679 ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
5680 ImGui::Separator();
5681 ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
5682 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
5683
5684 static bool show_config_info = false;
5685 ImGui::Checkbox("Config/Build Information", &show_config_info);
5686 if (show_config_info)
5687 {
5688 ImGuiIO& io = ImGui::GetIO();
5689 ImGuiStyle& style = ImGui::GetStyle();
5690
5691 bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
5692 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
5693 ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove);
5694 if (copy_to_clipboard)
5695 {
5696 ImGui::LogToClipboard();
5697 ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
5698 }
5699
5700 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
5701 ImGui::Separator();
5702 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
5703 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
5704 #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
5705 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
5706 #endif
5707 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
5708 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
5709 #endif
5710 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
5711 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
5712 #endif
5713 #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
5714 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
5715 #endif
5716 #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
5717 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
5718 #endif
5719 #ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
5720 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
5721 #endif
5722 #ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
5723 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
5724 #endif
5725 #ifdef IMGUI_DISABLE_FILE_FUNCTIONS
5726 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
5727 #endif
5728 #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
5729 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
5730 #endif
5731 #ifdef IMGUI_USE_BGRA_PACKED_COLOR
5732 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
5733 #endif
5734 #ifdef _WIN32
5735 ImGui::Text("define: _WIN32");
5736 #endif
5737 #ifdef _WIN64
5738 ImGui::Text("define: _WIN64");
5739 #endif
5740 #ifdef __linux__
5741 ImGui::Text("define: __linux__");
5742 #endif
5743 #ifdef __APPLE__
5744 ImGui::Text("define: __APPLE__");
5745 #endif
5746 #ifdef _MSC_VER
5747 ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
5748 #endif
5749 #ifdef _MSVC_LANG
5750 ImGui::Text("define: _MSVC_LANG=%d", (int)_MSVC_LANG);
5751 #endif
5752 #ifdef __MINGW32__
5753 ImGui::Text("define: __MINGW32__");
5754 #endif
5755 #ifdef __MINGW64__
5756 ImGui::Text("define: __MINGW64__");
5757 #endif
5758 #ifdef __GNUC__
5759 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
5760 #endif
5761 #ifdef __clang_version__
5762 ImGui::Text("define: __clang_version__=%s", __clang_version__);
5763 #endif
5764 #ifdef IMGUI_HAS_VIEWPORT
5765 ImGui::Text("define: IMGUI_HAS_VIEWPORT");
5766 #endif
5767 #ifdef IMGUI_HAS_DOCK
5768 ImGui::Text("define: IMGUI_HAS_DOCK");
5769 #endif
5770 ImGui::Separator();
5771 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
5772 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
5773 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
5774 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
5775 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
5776 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos");
5777 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard");
5778 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
5779 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
5780 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable");
5781 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable");
5782 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports");
5783 if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleFonts) ImGui::Text(" DpiEnableScaleFonts");
5784 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
5785 if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge");
5786 if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon");
5787 if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration");
5788 if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent");
5789 if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit");
5790 if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar");
5791 if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload");
5792 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
5793 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
5794 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
5795 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
5796 if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer);
5797 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
5798 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
5799 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
5800 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
5801 if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports");
5802 if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport");
5803 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
5804 if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports");
5805 ImGui::Separator();
5806 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);
5807 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
5808 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
5809 ImGui::Separator();
5810 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
5811 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
5812 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
5813 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
5814 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
5815 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
5816 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
5817
5818 if (copy_to_clipboard)
5819 {
5820 ImGui::LogText("\n```\n");
5821 ImGui::LogFinish();
5822 }
5823 ImGui::EndChildFrame();
5824 }
5825 ImGui::End();
5826 }
5827
5828 //-----------------------------------------------------------------------------
5829 // [SECTION] Style Editor / ShowStyleEditor()
5830 //-----------------------------------------------------------------------------
5831 // - ShowFontSelector()
5832 // - ShowStyleSelector()
5833 // - ShowStyleEditor()
5834 //-----------------------------------------------------------------------------
5835
5836 // Forward declare ShowFontAtlas() which isn't worth putting in public API yet
5837 namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); }
5838
5839 // Demo helper function to select among loaded fonts.
5840 // Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one.
5841 void ImGui::ShowFontSelector(const char* label)
5842 {
5843 ImGuiIO& io = ImGui::GetIO();
5844 ImFont* font_current = ImGui::GetFont();
5845 if (ImGui::BeginCombo(label, font_current->GetDebugName()))
5846 {
5847 for (int n = 0; n < io.Fonts->Fonts.Size; n++)
5848 {
5849 ImFont* font = io.Fonts->Fonts[n];
5850 ImGui::PushID((void*)font);
5851 if (ImGui::Selectable(font->GetDebugName(), font == font_current))
5852 io.FontDefault = font;
5853 ImGui::PopID();
5854 }
5855 ImGui::EndCombo();
5856 }
5857 ImGui::SameLine();
5858 HelpMarker(
5859 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
5860 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
5861 "- Read FAQ and docs/FONTS.md for more details.\n"
5862 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
5863 }
5864
5865 // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
5866 // Here we use the simplified Combo() api that packs items into a single literal string.
5867 // Useful for quick combo boxes where the choices are known locally.
5868 bool ImGui::ShowStyleSelector(const char* label)
5869 {
5870 static int style_idx = -1;
5871 if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0"))
5872 {
5873 switch (style_idx)
5874 {
5875 case 0: ImGui::StyleColorsDark(); break;
5876 case 1: ImGui::StyleColorsLight(); break;
5877 case 2: ImGui::StyleColorsClassic(); break;
5878 }
5879 return true;
5880 }
5881 return false;
5882 }
5883
5884 void ImGui::ShowStyleEditor(ImGuiStyle* ref)
5885 {
5886 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
5887 // (without a reference style pointer, we will use one compared locally as a reference)
5888 ImGuiStyle& style = ImGui::GetStyle();
5889 static ImGuiStyle ref_saved_style;
5890
5891 // Default to using internal storage as reference
5892 static bool init = true;
5893 if (init && ref == NULL)
5894 ref_saved_style = style;
5895 init = false;
5896 if (ref == NULL)
5897 ref = &ref_saved_style;
5898
5899 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
5900
5901 if (ImGui::ShowStyleSelector("Colors##Selector"))
5902 ref_saved_style = style;
5903 ImGui::ShowFontSelector("Fonts##Selector");
5904
5905 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
5906 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
5907 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
5908 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
5909 ImGui::SameLine();
5910 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } }
5911 ImGui::SameLine();
5912 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } }
5913
5914 // Save/Revert button
5915 if (ImGui::Button("Save Ref"))
5916 *ref = ref_saved_style = style;
5917 ImGui::SameLine();
5918 if (ImGui::Button("Revert Ref"))
5919 style = *ref;
5920 ImGui::SameLine();
5921 HelpMarker(
5922 "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
5923 "Use \"Export\" below to save them somewhere.");
5924
5925 ImGui::Separator();
5926
5927 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
5928 {
5929 if (ImGui::BeginTabItem("Sizes"))
5930 {
5931 ImGui::Text("Main");
5932 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
5933 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
5934 ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
5935 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
5936 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
5937 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
5938 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
5939 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
5940 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
5941 ImGui::Text("Borders");
5942 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
5943 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
5944 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
5945 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
5946 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
5947 ImGui::Text("Rounding");
5948 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
5949 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
5950 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
5951 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
5952 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
5953 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
5954 ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
5955 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
5956 ImGui::Text("Alignment");
5957 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
5958 int window_menu_button_position = style.WindowMenuButtonPosition + 1;
5959 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
5960 style.WindowMenuButtonPosition = window_menu_button_position - 1;
5961 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
5962 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
5963 ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
5964 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
5965 ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
5966 ImGui::Text("Safe Area Padding");
5967 ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
5968 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
5969 ImGui::EndTabItem();
5970 }
5971
5972 if (ImGui::BeginTabItem("Colors"))
5973 {
5974 static int output_dest = 0;
5975 static bool output_only_modified = true;
5976 if (ImGui::Button("Export"))
5977 {
5978 if (output_dest == 0)
5979 ImGui::LogToClipboard();
5980 else
5981 ImGui::LogToTTY();
5982 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
5983 for (int i = 0; i < ImGuiCol_COUNT; i++)
5984 {
5985 const ImVec4& col = style.Colors[i];
5986 const char* name = ImGui::GetStyleColorName(i);
5987 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
5988 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
5989 name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
5990 }
5991 ImGui::LogFinish();
5992 }
5993 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
5994 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
5995
5996 static ImGuiTextFilter filter;
5997 filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
5998
5999 static ImGuiColorEditFlags alpha_flags = 0;
6000 if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
6001 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
6002 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
6003 HelpMarker(
6004 "In the color list:\n"
6005 "Left-click on color square to open color picker,\n"
6006 "Right-click to open edit options menu.");
6007
6008 ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
6009 ImGui::PushItemWidth(-160);
6010 for (int i = 0; i < ImGuiCol_COUNT; i++)
6011 {
6012 const char* name = ImGui::GetStyleColorName(i);
6013 if (!filter.PassFilter(name))
6014 continue;
6015 ImGui::PushID(i);
6016 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
6017 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
6018 {
6019 // Tips: in a real user application, you may want to merge and use an icon font into the main font,
6020 // so instead of "Save"/"Revert" you'd use icons!
6021 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
6022 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
6023 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
6024 }
6025 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
6026 ImGui::TextUnformatted(name);
6027 ImGui::PopID();
6028 }
6029 ImGui::PopItemWidth();
6030 ImGui::EndChild();
6031
6032 ImGui::EndTabItem();
6033 }
6034
6035 if (ImGui::BeginTabItem("Fonts"))
6036 {
6037 ImGuiIO& io = ImGui::GetIO();
6038 ImFontAtlas* atlas = io.Fonts;
6039 HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
6040 ImGui::ShowFontAtlas(atlas);
6041
6042 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
6043 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
6044 const float MIN_SCALE = 0.3f;
6045 const float MAX_SCALE = 2.0f;
6046 HelpMarker(
6047 "Those are old settings provided for convenience.\n"
6048 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
6049 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
6050 "Using those settings here will give you poor quality results.");
6051 static float window_scale = 1.0f;
6052 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
6053 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
6054 ImGui::SetWindowFontScale(window_scale);
6055 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
6056 ImGui::PopItemWidth();
6057
6058 ImGui::EndTabItem();
6059 }
6060
6061 if (ImGui::BeginTabItem("Rendering"))
6062 {
6063 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
6064 ImGui::SameLine();
6065 HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
6066
6067 ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
6068 ImGui::SameLine();
6069 HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering).");
6070
6071 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
6072 ImGui::PushItemWidth(ImGui::GetFontSize() * 8);
6073 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
6074 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
6075
6076 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
6077 ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
6078 if (ImGui::IsItemActive())
6079 {
6080 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
6081 ImGui::BeginTooltip();
6082 ImGui::TextUnformatted("(R = radius, N = number of segments)");
6083 ImGui::Spacing();
6084 ImDrawList* draw_list = ImGui::GetWindowDrawList();
6085 const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x;
6086 for (int n = 0; n < 8; n++)
6087 {
6088 const float RAD_MIN = 5.0f;
6089 const float RAD_MAX = 70.0f;
6090 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
6091
6092 ImGui::BeginGroup();
6093
6094 ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
6095
6096 const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
6097 const float offset_x = floorf(canvas_width * 0.5f);
6098 const float offset_y = floorf(RAD_MAX);
6099
6100 const ImVec2 p1 = ImGui::GetCursorScreenPos();
6101 draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
6102 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
6103
6104 /*
6105 const ImVec2 p2 = ImGui::GetCursorScreenPos();
6106 draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
6107 ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
6108 */
6109
6110 ImGui::EndGroup();
6111 ImGui::SameLine();
6112 }
6113 ImGui::EndTooltip();
6114 }
6115 ImGui::SameLine();
6116 HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
6117
6118 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.
6119 ImGui::PopItemWidth();
6120
6121 ImGui::EndTabItem();
6122 }
6123
6124 ImGui::EndTabBar();
6125 }
6126
6127 ImGui::PopItemWidth();
6128 }
6129
6130 //-----------------------------------------------------------------------------
6131 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
6132 //-----------------------------------------------------------------------------
6133 // - ShowExampleAppMainMenuBar()
6134 // - ShowExampleMenuFile()
6135 //-----------------------------------------------------------------------------
6136
6137 // Demonstrate creating a "main" fullscreen menu bar and populating it.
6138 // Note the difference between BeginMainMenuBar() and BeginMenuBar():
6139 // - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
6140 // - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
6141 static void ShowExampleAppMainMenuBar()
6142 {
6143 if (ImGui::BeginMainMenuBar())
6144 {
6145 if (ImGui::BeginMenu("File"))
6146 {
6147 ShowExampleMenuFile();
6148 ImGui::EndMenu();
6149 }
6150 if (ImGui::BeginMenu("Edit"))
6151 {
6152 if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
6153 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
6154 ImGui::Separator();
6155 if (ImGui::MenuItem("Cut", "CTRL+X")) {}
6156 if (ImGui::MenuItem("Copy", "CTRL+C")) {}
6157 if (ImGui::MenuItem("Paste", "CTRL+V")) {}
6158 ImGui::EndMenu();
6159 }
6160 ImGui::EndMainMenuBar();
6161 }
6162 }
6163
6164 // Note that shortcuts are currently provided for display only
6165 // (future version will add explicit flags to BeginMenu() to request processing shortcuts)
6166 static void ShowExampleMenuFile()
6167 {
6168 ImGui::MenuItem("(demo menu)", NULL, false, false);
6169 if (ImGui::MenuItem("New")) {}
6170 if (ImGui::MenuItem("Open", "Ctrl+O")) {}
6171 if (ImGui::BeginMenu("Open Recent"))
6172 {
6173 ImGui::MenuItem("fish_hat.c");
6174 ImGui::MenuItem("fish_hat.inl");
6175 ImGui::MenuItem("fish_hat.h");
6176 if (ImGui::BeginMenu("More.."))
6177 {
6178 ImGui::MenuItem("Hello");
6179 ImGui::MenuItem("Sailor");
6180 if (ImGui::BeginMenu("Recurse.."))
6181 {
6182 ShowExampleMenuFile();
6183 ImGui::EndMenu();
6184 }
6185 ImGui::EndMenu();
6186 }
6187 ImGui::EndMenu();
6188 }
6189 if (ImGui::MenuItem("Save", "Ctrl+S")) {}
6190 if (ImGui::MenuItem("Save As..")) {}
6191
6192 ImGui::Separator();
6193 if (ImGui::BeginMenu("Options"))
6194 {
6195 static bool enabled = true;
6196 ImGui::MenuItem("Enabled", "", &enabled);
6197 ImGui::BeginChild("child", ImVec2(0, 60), true);
6198 for (int i = 0; i < 10; i++)
6199 ImGui::Text("Scrolling Text %d", i);
6200 ImGui::EndChild();
6201 static float f = 0.5f;
6202 static int n = 0;
6203 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
6204 ImGui::InputFloat("Input", &f, 0.1f);
6205 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
6206 ImGui::EndMenu();
6207 }
6208
6209 if (ImGui::BeginMenu("Colors"))
6210 {
6211 float sz = ImGui::GetTextLineHeight();
6212 for (int i = 0; i < ImGuiCol_COUNT; i++)
6213 {
6214 const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
6215 ImVec2 p = ImGui::GetCursorScreenPos();
6216 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
6217 ImGui::Dummy(ImVec2(sz, sz));
6218 ImGui::SameLine();
6219 ImGui::MenuItem(name);
6220 }
6221 ImGui::EndMenu();
6222 }
6223
6224 // Here we demonstrate appending again to the "Options" menu (which we already created above)
6225 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
6226 // In a real code-base using it would make senses to use this feature from very different code locations.
6227 if (ImGui::BeginMenu("Options")) // <-- Append!
6228 {
6229 static bool b = true;
6230 ImGui::Checkbox("SomeOption", &b);
6231 ImGui::EndMenu();
6232 }
6233
6234 if (ImGui::BeginMenu("Disabled", false)) // Disabled
6235 {
6236 IM_ASSERT(0);
6237 }
6238 if (ImGui::MenuItem("Checked", NULL, true)) {}
6239 if (ImGui::MenuItem("Quit", "Alt+F4")) {}
6240 }
6241
6242 //-----------------------------------------------------------------------------
6243 // [SECTION] Example App: Debug Console / ShowExampleAppConsole()
6244 //-----------------------------------------------------------------------------
6245
6246 // Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
6247 // For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
6248 struct ExampleAppConsole
6249 {
6250 char InputBuf[256];
6251 ImVector<char*> Items;
6252 ImVector<const char*> Commands;
6253 ImVector<char*> History;
6254 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
6255 ImGuiTextFilter Filter;
6256 bool AutoScroll;
6257 bool ScrollToBottom;
6258
6259 ExampleAppConsole()
6260 {
6261 ClearLog();
6262 memset(InputBuf, 0, sizeof(InputBuf));
6263 HistoryPos = -1;
6264
6265 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
6266 Commands.push_back("HELP");
6267 Commands.push_back("HISTORY");
6268 Commands.push_back("CLEAR");
6269 Commands.push_back("CLASSIFY");
6270 AutoScroll = true;
6271 ScrollToBottom = false;
6272 AddLog("Welcome to Dear ImGui!");
6273 }
6274 ~ExampleAppConsole()
6275 {
6276 ClearLog();
6277 for (int i = 0; i < History.Size; i++)
6278 free(History[i]);
6279 }
6280
6281 // Portable helpers
6282 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
6283 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; }
6284 static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
6285 static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
6286
6287 void ClearLog()
6288 {
6289 for (int i = 0; i < Items.Size; i++)
6290 free(Items[i]);
6291 Items.clear();
6292 }
6293
6294 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
6295 {
6296 // FIXME-OPT
6297 char buf[1024];
6298 va_list args;
6299 va_start(args, fmt);
6300 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
6301 buf[IM_ARRAYSIZE(buf)-1] = 0;
6302 va_end(args);
6303 Items.push_back(Strdup(buf));
6304 }
6305
6306 void Draw(const char* title, bool* p_open)
6307 {
6308 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
6309 if (!ImGui::Begin(title, p_open))
6310 {
6311 ImGui::End();
6312 return;
6313 }
6314
6315 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
6316 // So e.g. IsItemHovered() will return true when hovering the title bar.
6317 // Here we create a context menu only available from the title bar.
6318 if (ImGui::BeginPopupContextItem())
6319 {
6320 if (ImGui::MenuItem("Close Console"))
6321 *p_open = false;
6322 ImGui::EndPopup();
6323 }
6324
6325 ImGui::TextWrapped(
6326 "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
6327 "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
6328 ImGui::TextWrapped("Enter 'HELP' for help.");
6329
6330 // TODO: display items starting from the bottom
6331
6332 if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
6333 ImGui::SameLine();
6334 if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
6335 ImGui::SameLine();
6336 if (ImGui::SmallButton("Clear")) { ClearLog(); }
6337 ImGui::SameLine();
6338 bool copy_to_clipboard = ImGui::SmallButton("Copy");
6339 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
6340
6341 ImGui::Separator();
6342
6343 // Options menu
6344 if (ImGui::BeginPopup("Options"))
6345 {
6346 ImGui::Checkbox("Auto-scroll", &AutoScroll);
6347 ImGui::EndPopup();
6348 }
6349
6350 // Options, Filter
6351 if (ImGui::Button("Options"))
6352 ImGui::OpenPopup("Options");
6353 ImGui::SameLine();
6354 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
6355 ImGui::Separator();
6356
6357 // Reserve enough left-over height for 1 separator + 1 input text
6358 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
6359 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar);
6360 if (ImGui::BeginPopupContextWindow())
6361 {
6362 if (ImGui::Selectable("Clear")) ClearLog();
6363 ImGui::EndPopup();
6364 }
6365
6366 // Display every line as a separate entry so we can change their color or add custom widgets.
6367 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
6368 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
6369 // to only process visible items. The clipper will automatically measure the height of your first item and then
6370 // "seek" to display only items in the visible area.
6371 // To use the clipper we can replace your standard loop:
6372 // for (int i = 0; i < Items.Size; i++)
6373 // With:
6374 // ImGuiListClipper clipper;
6375 // clipper.Begin(Items.Size);
6376 // while (clipper.Step())
6377 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
6378 // - That your items are evenly spaced (same height)
6379 // - That you have cheap random access to your elements (you can access them given their index,
6380 // without processing all the ones before)
6381 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
6382 // We would need random-access on the post-filtered list.
6383 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
6384 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
6385 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
6386 // to improve this example code!
6387 // If your items are of variable height:
6388 // - Split them into same height items would be simpler and facilitate random-seeking into your list.
6389 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
6390 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
6391 if (copy_to_clipboard)
6392 ImGui::LogToClipboard();
6393 for (int i = 0; i < Items.Size; i++)
6394 {
6395 const char* item = Items[i];
6396 if (!Filter.PassFilter(item))
6397 continue;
6398
6399 // Normally you would store more information in your item than just a string.
6400 // (e.g. make Items[] an array of structure, store color/type etc.)
6401 ImVec4 color;
6402 bool has_color = false;
6403 if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
6404 else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
6405 if (has_color)
6406 ImGui::PushStyleColor(ImGuiCol_Text, color);
6407 ImGui::TextUnformatted(item);
6408 if (has_color)
6409 ImGui::PopStyleColor();
6410 }
6411 if (copy_to_clipboard)
6412 ImGui::LogFinish();
6413
6414 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
6415 ImGui::SetScrollHereY(1.0f);
6416 ScrollToBottom = false;
6417
6418 ImGui::PopStyleVar();
6419 ImGui::EndChild();
6420 ImGui::Separator();
6421
6422 // Command-line
6423 bool reclaim_focus = false;
6424 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
6425 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
6426 {
6427 char* s = InputBuf;
6428 Strtrim(s);
6429 if (s[0])
6430 ExecCommand(s);
6431 strcpy(s, "");
6432 reclaim_focus = true;
6433 }
6434
6435 // Auto-focus on window apparition
6436 ImGui::SetItemDefaultFocus();
6437 if (reclaim_focus)
6438 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
6439
6440 ImGui::End();
6441 }
6442
6443 void ExecCommand(const char* command_line)
6444 {
6445 AddLog("# %s\n", command_line);
6446
6447 // Insert into history. First find match and delete it so it can be pushed to the back.
6448 // This isn't trying to be smart or optimal.
6449 HistoryPos = -1;
6450 for (int i = History.Size - 1; i >= 0; i--)
6451 if (Stricmp(History[i], command_line) == 0)
6452 {
6453 free(History[i]);
6454 History.erase(History.begin() + i);
6455 break;
6456 }
6457 History.push_back(Strdup(command_line));
6458
6459 // Process command
6460 if (Stricmp(command_line, "CLEAR") == 0)
6461 {
6462 ClearLog();
6463 }
6464 else if (Stricmp(command_line, "HELP") == 0)
6465 {
6466 AddLog("Commands:");
6467 for (int i = 0; i < Commands.Size; i++)
6468 AddLog("- %s", Commands[i]);
6469 }
6470 else if (Stricmp(command_line, "HISTORY") == 0)
6471 {
6472 int first = History.Size - 10;
6473 for (int i = first > 0 ? first : 0; i < History.Size; i++)
6474 AddLog("%3d: %s\n", i, History[i]);
6475 }
6476 else
6477 {
6478 AddLog("Unknown command: '%s'\n", command_line);
6479 }
6480
6481 // On command input, we scroll to bottom even if AutoScroll==false
6482 ScrollToBottom = true;
6483 }
6484
6485 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
6486 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
6487 {
6488 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
6489 return console->TextEditCallback(data);
6490 }
6491
6492 int TextEditCallback(ImGuiInputTextCallbackData* data)
6493 {
6494 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
6495 switch (data->EventFlag)
6496 {
6497 case ImGuiInputTextFlags_CallbackCompletion:
6498 {
6499 // Example of TEXT COMPLETION
6500
6501 // Locate beginning of current word
6502 const char* word_end = data->Buf + data->CursorPos;
6503 const char* word_start = word_end;
6504 while (word_start > data->Buf)
6505 {
6506 const char c = word_start[-1];
6507 if (c == ' ' || c == '\t' || c == ',' || c == ';')
6508 break;
6509 word_start--;
6510 }
6511
6512 // Build a list of candidates
6513 ImVector<const char*> candidates;
6514 for (int i = 0; i < Commands.Size; i++)
6515 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
6516 candidates.push_back(Commands[i]);
6517
6518 if (candidates.Size == 0)
6519 {
6520 // No match
6521 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
6522 }
6523 else if (candidates.Size == 1)
6524 {
6525 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
6526 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
6527 data->InsertChars(data->CursorPos, candidates[0]);
6528 data->InsertChars(data->CursorPos, " ");
6529 }
6530 else
6531 {
6532 // Multiple matches. Complete as much as we can..
6533 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
6534 int match_len = (int)(word_end - word_start);
6535 for (;;)
6536 {
6537 int c = 0;
6538 bool all_candidates_matches = true;
6539 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
6540 if (i == 0)
6541 c = toupper(candidates[i][match_len]);
6542 else if (c == 0 || c != toupper(candidates[i][match_len]))
6543 all_candidates_matches = false;
6544 if (!all_candidates_matches)
6545 break;
6546 match_len++;
6547 }
6548
6549 if (match_len > 0)
6550 {
6551 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
6552 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
6553 }
6554
6555 // List matches
6556 AddLog("Possible matches:\n");
6557 for (int i = 0; i < candidates.Size; i++)
6558 AddLog("- %s\n", candidates[i]);
6559 }
6560
6561 break;
6562 }
6563 case ImGuiInputTextFlags_CallbackHistory:
6564 {
6565 // Example of HISTORY
6566 const int prev_history_pos = HistoryPos;
6567 if (data->EventKey == ImGuiKey_UpArrow)
6568 {
6569 if (HistoryPos == -1)
6570 HistoryPos = History.Size - 1;
6571 else if (HistoryPos > 0)
6572 HistoryPos--;
6573 }
6574 else if (data->EventKey == ImGuiKey_DownArrow)
6575 {
6576 if (HistoryPos != -1)
6577 if (++HistoryPos >= History.Size)
6578 HistoryPos = -1;
6579 }
6580
6581 // A better implementation would preserve the data on the current input line along with cursor position.
6582 if (prev_history_pos != HistoryPos)
6583 {
6584 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
6585 data->DeleteChars(0, data->BufTextLen);
6586 data->InsertChars(0, history_str);
6587 }
6588 }
6589 }
6590 return 0;
6591 }
6592 };
6593
6594 static void ShowExampleAppConsole(bool* p_open)
6595 {
6596 static ExampleAppConsole console;
6597 console.Draw("Example: Console", p_open);
6598 }
6599
6600 //-----------------------------------------------------------------------------
6601 // [SECTION] Example App: Debug Log / ShowExampleAppLog()
6602 //-----------------------------------------------------------------------------
6603
6604 // Usage:
6605 // static ExampleAppLog my_log;
6606 // my_log.AddLog("Hello %d world\n", 123);
6607 // my_log.Draw("title");
6608 struct ExampleAppLog
6609 {
6610 ImGuiTextBuffer Buf;
6611 ImGuiTextFilter Filter;
6612 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
6613 bool AutoScroll; // Keep scrolling if already at the bottom.
6614
6615 ExampleAppLog()
6616 {
6617 AutoScroll = true;
6618 Clear();
6619 }
6620
6621 void Clear()
6622 {
6623 Buf.clear();
6624 LineOffsets.clear();
6625 LineOffsets.push_back(0);
6626 }
6627
6628 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
6629 {
6630 int old_size = Buf.size();
6631 va_list args;
6632 va_start(args, fmt);
6633 Buf.appendfv(fmt, args);
6634 va_end(args);
6635 for (int new_size = Buf.size(); old_size < new_size; old_size++)
6636 if (Buf[old_size] == '\n')
6637 LineOffsets.push_back(old_size + 1);
6638 }
6639
6640 void Draw(const char* title, bool* p_open = NULL)
6641 {
6642 if (!ImGui::Begin(title, p_open))
6643 {
6644 ImGui::End();
6645 return;
6646 }
6647
6648 // Options menu
6649 if (ImGui::BeginPopup("Options"))
6650 {
6651 ImGui::Checkbox("Auto-scroll", &AutoScroll);
6652 ImGui::EndPopup();
6653 }
6654
6655 // Main window
6656 if (ImGui::Button("Options"))
6657 ImGui::OpenPopup("Options");
6658 ImGui::SameLine();
6659 bool clear = ImGui::Button("Clear");
6660 ImGui::SameLine();
6661 bool copy = ImGui::Button("Copy");
6662 ImGui::SameLine();
6663 Filter.Draw("Filter", -100.0f);
6664
6665 ImGui::Separator();
6666 ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
6667
6668 if (clear)
6669 Clear();
6670 if (copy)
6671 ImGui::LogToClipboard();
6672
6673 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
6674 const char* buf = Buf.begin();
6675 const char* buf_end = Buf.end();
6676 if (Filter.IsActive())
6677 {
6678 // In this example we don't use the clipper when Filter is enabled.
6679 // This is because we don't have a random access on the result on our filter.
6680 // A real application processing logs with ten of thousands of entries may want to store the result of
6681 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
6682 for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
6683 {
6684 const char* line_start = buf + LineOffsets[line_no];
6685 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
6686 if (Filter.PassFilter(line_start, line_end))
6687 ImGui::TextUnformatted(line_start, line_end);
6688 }
6689 }
6690 else
6691 {
6692 // The simplest and easy way to display the entire buffer:
6693 // ImGui::TextUnformatted(buf_begin, buf_end);
6694 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
6695 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
6696 // within the visible area.
6697 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
6698 // on your side is recommended. Using ImGuiListClipper requires
6699 // - A) random access into your data
6700 // - B) items all being the same height,
6701 // both of which we can handle since we an array pointing to the beginning of each line of text.
6702 // When using the filter (in the block of code above) we don't have random access into the data to display
6703 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
6704 // it possible (and would be recommended if you want to search through tens of thousands of entries).
6705 ImGuiListClipper clipper;
6706 clipper.Begin(LineOffsets.Size);
6707 while (clipper.Step())
6708 {
6709 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
6710 {
6711 const char* line_start = buf + LineOffsets[line_no];
6712 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
6713 ImGui::TextUnformatted(line_start, line_end);
6714 }
6715 }
6716 clipper.End();
6717 }
6718 ImGui::PopStyleVar();
6719
6720 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
6721 ImGui::SetScrollHereY(1.0f);
6722
6723 ImGui::EndChild();
6724 ImGui::End();
6725 }
6726 };
6727
6728 // Demonstrate creating a simple log window with basic filtering.
6729 static void ShowExampleAppLog(bool* p_open)
6730 {
6731 static ExampleAppLog log;
6732
6733 // For the demo: add a debug button _BEFORE_ the normal log window contents
6734 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
6735 // Most of the contents of the window will be added by the log.Draw() call.
6736 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
6737 ImGui::Begin("Example: Log", p_open);
6738 if (ImGui::SmallButton("[Debug] Add 5 entries"))
6739 {
6740 static int counter = 0;
6741 const char* categories[3] = { "info", "warn", "error" };
6742 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
6743 for (int n = 0; n < 5; n++)
6744 {
6745 const char* category = categories[counter % IM_ARRAYSIZE(categories)];
6746 const char* word = words[counter % IM_ARRAYSIZE(words)];
6747 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
6748 ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
6749 counter++;
6750 }
6751 }
6752 ImGui::End();
6753
6754 // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
6755 log.Draw("Example: Log", p_open);
6756 }
6757
6758 //-----------------------------------------------------------------------------
6759 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
6760 //-----------------------------------------------------------------------------
6761
6762 // Demonstrate create a window with multiple child windows.
6763 static void ShowExampleAppLayout(bool* p_open)
6764 {
6765 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
6766 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
6767 {
6768 if (ImGui::BeginMenuBar())
6769 {
6770 if (ImGui::BeginMenu("File"))
6771 {
6772 if (ImGui::MenuItem("Close")) *p_open = false;
6773 ImGui::EndMenu();
6774 }
6775 ImGui::EndMenuBar();
6776 }
6777
6778 // Left
6779 static int selected = 0;
6780 {
6781 ImGui::BeginChild("left pane", ImVec2(150, 0), true);
6782 for (int i = 0; i < 100; i++)
6783 {
6784 // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
6785 char label[128];
6786 sprintf(label, "MyObject %d", i);
6787 if (ImGui::Selectable(label, selected == i))
6788 selected = i;
6789 }
6790 ImGui::EndChild();
6791 }
6792 ImGui::SameLine();
6793
6794 // Right
6795 {
6796 ImGui::BeginGroup();
6797 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
6798 ImGui::Text("MyObject: %d", selected);
6799 ImGui::Separator();
6800 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
6801 {
6802 if (ImGui::BeginTabItem("Description"))
6803 {
6804 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
6805 ImGui::EndTabItem();
6806 }
6807 if (ImGui::BeginTabItem("Details"))
6808 {
6809 ImGui::Text("ID: 0123456789");
6810 ImGui::EndTabItem();
6811 }
6812 ImGui::EndTabBar();
6813 }
6814 ImGui::EndChild();
6815 if (ImGui::Button("Revert")) {}
6816 ImGui::SameLine();
6817 if (ImGui::Button("Save")) {}
6818 ImGui::EndGroup();
6819 }
6820 }
6821 ImGui::End();
6822 }
6823
6824 //-----------------------------------------------------------------------------
6825 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
6826 //-----------------------------------------------------------------------------
6827
6828 static void ShowPlaceholderObject(const char* prefix, int uid)
6829 {
6830 // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
6831 ImGui::PushID(uid);
6832
6833 // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high.
6834 ImGui::TableNextRow();
6835 ImGui::TableSetColumnIndex(0);
6836 ImGui::AlignTextToFramePadding();
6837 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
6838 ImGui::TableSetColumnIndex(1);
6839 ImGui::Text("my sailor is rich");
6840
6841 if (node_open)
6842 {
6843 static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f };
6844 for (int i = 0; i < 8; i++)
6845 {
6846 ImGui::PushID(i); // Use field index as identifier.
6847 if (i < 2)
6848 {
6849 ShowPlaceholderObject("Child", 424242);
6850 }
6851 else
6852 {
6853 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well)
6854 ImGui::TableNextRow();
6855 ImGui::TableSetColumnIndex(0);
6856 ImGui::AlignTextToFramePadding();
6857 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet;
6858 ImGui::TreeNodeEx("Field", flags, "Field_%d", i);
6859
6860 ImGui::TableSetColumnIndex(1);
6861 ImGui::SetNextItemWidth(-FLT_MIN);
6862 if (i >= 5)
6863 ImGui::InputFloat("##value", &placeholder_members[i], 1.0f);
6864 else
6865 ImGui::DragFloat("##value", &placeholder_members[i], 0.01f);
6866 ImGui::NextColumn();
6867 }
6868 ImGui::PopID();
6869 }
6870 ImGui::TreePop();
6871 }
6872 ImGui::PopID();
6873 }
6874
6875 // Demonstrate create a simple property editor.
6876 static void ShowExampleAppPropertyEditor(bool* p_open)
6877 {
6878 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
6879 if (!ImGui::Begin("Example: Property editor", p_open))
6880 {
6881 ImGui::End();
6882 return;
6883 }
6884
6885 HelpMarker(
6886 "This example shows how you may implement a property editor using two columns.\n"
6887 "All objects/fields data are dummies here.\n"
6888 "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n"
6889 "your cursor horizontally instead of using the Columns() API.");
6890
6891 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
6892 if (ImGui::BeginTable("split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable))
6893 {
6894 // Iterate placeholder objects (all the same data)
6895 for (int obj_i = 0; obj_i < 4; obj_i++)
6896 {
6897 ShowPlaceholderObject("Object", obj_i);
6898 //ImGui::Separator();
6899 }
6900 ImGui::EndTable();
6901 }
6902 ImGui::PopStyleVar();
6903 ImGui::End();
6904 }
6905
6906 //-----------------------------------------------------------------------------
6907 // [SECTION] Example App: Long Text / ShowExampleAppLongText()
6908 //-----------------------------------------------------------------------------
6909
6910 // Demonstrate/test rendering huge amount of text, and the incidence of clipping.
6911 static void ShowExampleAppLongText(bool* p_open)
6912 {
6913 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
6914 if (!ImGui::Begin("Example: Long text display", p_open))
6915 {
6916 ImGui::End();
6917 return;
6918 }
6919
6920 static int test_type = 0;
6921 static ImGuiTextBuffer log;
6922 static int lines = 0;
6923 ImGui::Text("Printing unusually long amount of text.");
6924 ImGui::Combo("Test type", &test_type,
6925 "Single call to TextUnformatted()\0"
6926 "Multiple calls to Text(), clipped\0"
6927 "Multiple calls to Text(), not clipped (slow)\0");
6928 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
6929 if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
6930 ImGui::SameLine();
6931 if (ImGui::Button("Add 1000 lines"))
6932 {
6933 for (int i = 0; i < 1000; i++)
6934 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
6935 lines += 1000;
6936 }
6937 ImGui::BeginChild("Log");
6938 switch (test_type)
6939 {
6940 case 0:
6941 // Single call to TextUnformatted() with a big buffer
6942 ImGui::TextUnformatted(log.begin(), log.end());
6943 break;
6944 case 1:
6945 {
6946 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
6947 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
6948 ImGuiListClipper clipper;
6949 clipper.Begin(lines);
6950 while (clipper.Step())
6951 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
6952 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
6953 ImGui::PopStyleVar();
6954 break;
6955 }
6956 case 2:
6957 // Multiple calls to Text(), not clipped (slow)
6958 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
6959 for (int i = 0; i < lines; i++)
6960 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
6961 ImGui::PopStyleVar();
6962 break;
6963 }
6964 ImGui::EndChild();
6965 ImGui::End();
6966 }
6967
6968 //-----------------------------------------------------------------------------
6969 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
6970 //-----------------------------------------------------------------------------
6971
6972 // Demonstrate creating a window which gets auto-resized according to its content.
6973 static void ShowExampleAppAutoResize(bool* p_open)
6974 {
6975 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
6976 {
6977 ImGui::End();
6978 return;
6979 }
6980
6981 static int lines = 10;
6982 ImGui::TextUnformatted(
6983 "Window will resize every-frame to the size of its content.\n"
6984 "Note that you probably don't want to query the window size to\n"
6985 "output your content because that would create a feedback loop.");
6986 ImGui::SliderInt("Number of lines", &lines, 1, 20);
6987 for (int i = 0; i < lines; i++)
6988 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
6989 ImGui::End();
6990 }
6991
6992 //-----------------------------------------------------------------------------
6993 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
6994 //-----------------------------------------------------------------------------
6995
6996 // Demonstrate creating a window with custom resize constraints.
6997 static void ShowExampleAppConstrainedResize(bool* p_open)
6998 {
6999 struct CustomConstraints
7000 {
7001 // Helper functions to demonstrate programmatic constraints
7002 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); }
7003 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); }
7004 };
7005
7006 const char* test_desc[] =
7007 {
7008 "Resize vertical only",
7009 "Resize horizontal only",
7010 "Width > 100, Height > 100",
7011 "Width 400-500",
7012 "Height 400-500",
7013 "Custom: Always Square",
7014 "Custom: Fixed Steps (100)",
7015 };
7016
7017 static bool auto_resize = false;
7018 static int type = 0;
7019 static int display_lines = 10;
7020 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only
7021 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only
7022 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
7023 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500
7024 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500
7025 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
7026 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step
7027
7028 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
7029 if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
7030 {
7031 if (ImGui::IsWindowDocked())
7032 ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
7033 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
7034 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
7035 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
7036 ImGui::SetNextItemWidth(200);
7037 ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
7038 ImGui::SetNextItemWidth(200);
7039 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
7040 ImGui::Checkbox("Auto-resize", &auto_resize);
7041 for (int i = 0; i < display_lines; i++)
7042 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
7043 }
7044 ImGui::End();
7045 }
7046
7047 //-----------------------------------------------------------------------------
7048 // [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay()
7049 //-----------------------------------------------------------------------------
7050
7051 // Demonstrate creating a simple static window with no decoration
7052 // + a context-menu to choose which corner of the screen to use.
7053 static void ShowExampleAppSimpleOverlay(bool* p_open)
7054 {
7055 static int corner = 0;
7056 ImGuiIO& io = ImGui::GetIO();
7057 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
7058 if (corner != -1)
7059 {
7060 const float PAD = 10.0f;
7061 const ImGuiViewport* viewport = ImGui::GetMainViewport();
7062 ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
7063 ImVec2 work_size = viewport->WorkSize;
7064 ImVec2 window_pos, window_pos_pivot;
7065 window_pos.x = (corner & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
7066 window_pos.y = (corner & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
7067 window_pos_pivot.x = (corner & 1) ? 1.0f : 0.0f;
7068 window_pos_pivot.y = (corner & 2) ? 1.0f : 0.0f;
7069 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
7070 ImGui::SetNextWindowViewport(viewport->ID);
7071 window_flags |= ImGuiWindowFlags_NoMove;
7072 }
7073 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
7074 if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
7075 {
7076 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
7077 ImGui::Separator();
7078 if (ImGui::IsMousePosValid())
7079 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
7080 else
7081 ImGui::Text("Mouse Position: <invalid>");
7082 if (ImGui::BeginPopupContextWindow())
7083 {
7084 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1;
7085 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0;
7086 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1;
7087 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2;
7088 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3;
7089 if (p_open && ImGui::MenuItem("Close")) *p_open = false;
7090 ImGui::EndPopup();
7091 }
7092 }
7093 ImGui::End();
7094 }
7095
7096 //-----------------------------------------------------------------------------
7097 // [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen()
7098 //-----------------------------------------------------------------------------
7099
7100 // Demonstrate creating a window covering the entire screen/viewport
7101 static void ShowExampleAppFullscreen(bool* p_open)
7102 {
7103 static bool use_work_area = true;
7104 static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;
7105
7106 // We demonstrate using the full viewport area or the work area (without menu-bars, task-bars etc.)
7107 // Based on your use case you may want one of the other.
7108 const ImGuiViewport* viewport = ImGui::GetMainViewport();
7109 ImGui::SetNextWindowPos(use_work_area ? viewport->WorkPos : viewport->Pos);
7110 ImGui::SetNextWindowSize(use_work_area ? viewport->WorkSize : viewport->Size);
7111
7112 if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
7113 {
7114 ImGui::Checkbox("Use work area instead of main area", &use_work_area);
7115 ImGui::SameLine();
7116 HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.");
7117
7118 ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground);
7119 ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration);
7120 ImGui::Indent();
7121 ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar);
7122 ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse);
7123 ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar);
7124 ImGui::Unindent();
7125
7126 if (p_open && ImGui::Button("Close this window"))
7127 *p_open = false;
7128 }
7129 ImGui::End();
7130 }
7131
7132 //-----------------------------------------------------------------------------
7133 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
7134 //-----------------------------------------------------------------------------
7135
7136 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation.
7137 // This apply to all regular items as well.
7138 // Read FAQ section "How can I have multiple widgets with the same label?" for details.
7139 static void ShowExampleAppWindowTitles(bool*)
7140 {
7141 const ImGuiViewport* viewport = ImGui::GetMainViewport();
7142 const ImVec2 base_pos = viewport->Pos;
7143
7144 // By default, Windows are uniquely identified by their title.
7145 // You can use the "##" and "###" markers to manipulate the display/ID.
7146
7147 // Using "##" to display same title but have unique identifier.
7148 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
7149 ImGui::Begin("Same title as another window##1");
7150 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
7151 ImGui::End();
7152
7153 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
7154 ImGui::Begin("Same title as another window##2");
7155 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
7156 ImGui::End();
7157
7158 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
7159 char buf[128];
7160 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
7161 ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
7162 ImGui::Begin(buf);
7163 ImGui::Text("This window has a changing title.");
7164 ImGui::End();
7165 }
7166
7167 //-----------------------------------------------------------------------------
7168 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
7169 //-----------------------------------------------------------------------------
7170
7171 // Demonstrate using the low-level ImDrawList to draw custom shapes.
7172 static void ShowExampleAppCustomRendering(bool* p_open)
7173 {
7174 if (!ImGui::Begin("Example: Custom rendering", p_open))
7175 {
7176 ImGui::End();
7177 return;
7178 }
7179
7180 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
7181 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
7182 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
7183 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
7184
7185 if (ImGui::BeginTabBar("##TabBar"))
7186 {
7187 if (ImGui::BeginTabItem("Primitives"))
7188 {
7189 ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
7190 ImDrawList* draw_list = ImGui::GetWindowDrawList();
7191
7192 // Draw gradients
7193 // (note that those are currently exacerbating our sRGB/Linear issues)
7194 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
7195 ImGui::Text("Gradients");
7196 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
7197 {
7198 ImVec2 p0 = ImGui::GetCursorScreenPos();
7199 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
7200 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
7201 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
7202 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
7203 ImGui::InvisibleButton("##gradient1", gradient_size);
7204 }
7205 {
7206 ImVec2 p0 = ImGui::GetCursorScreenPos();
7207 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
7208 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
7209 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
7210 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
7211 ImGui::InvisibleButton("##gradient2", gradient_size);
7212 }
7213
7214 // Draw a bunch of primitives
7215 ImGui::Text("All primitives");
7216 static float sz = 36.0f;
7217 static float thickness = 3.0f;
7218 static int ngon_sides = 6;
7219 static bool circle_segments_override = false;
7220 static int circle_segments_override_v = 12;
7221 static bool curve_segments_override = false;
7222 static int curve_segments_override_v = 8;
7223 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
7224 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f");
7225 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
7226 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
7227 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
7228 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7229 circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
7230 ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
7231 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
7232 curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
7233 ImGui::ColorEdit4("Color", &colf.x);
7234
7235 const ImVec2 p = ImGui::GetCursorScreenPos();
7236 const ImU32 col = ImColor(colf);
7237 const float spacing = 10.0f;
7238 const ImDrawFlags corners_tl_br = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomRight;
7239 const float rounding = sz / 5.0f;
7240 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
7241 const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
7242 float x = p.x + 4.0f;
7243 float y = p.y + 4.0f;
7244 for (int n = 0; n < 2; n++)
7245 {
7246 // First line uses a thickness of 1.0f, second line uses the configurable thickness
7247 float th = (n == 0) ? 1.0f : thickness;
7248 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon
7249 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle
7250 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square
7251 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners
7252 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners
7253 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
7254 //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
7255 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!)
7256 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
7257 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
7258
7259 // Quadratic Bezier Curve (3 control points)
7260 ImVec2 cp3[3] = { ImVec2(x, y + sz * 0.6f), ImVec2(x + sz * 0.5f, y - sz * 0.4f), ImVec2(x + sz, y + sz) };
7261 draw_list->AddBezierQuadratic(cp3[0], cp3[1], cp3[2], col, th, curve_segments); x += sz + spacing;
7262
7263 // Cubic Bezier Curve (4 control points)
7264 ImVec2 cp4[4] = { 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) };
7265 draw_list->AddBezierCubic(cp4[0], cp4[1], cp4[2], cp4[3], col, th, curve_segments);
7266
7267 x = p.x + 4;
7268 y += sz + spacing;
7269 }
7270 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon
7271 draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments); x += sz + spacing; // Circle
7272 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square
7273 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners
7274 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
7275 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
7276 //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
7277 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)
7278 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)
7279 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine)
7280 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));
7281
7282 ImGui::Dummy(ImVec2((sz + spacing) * 10.2f, (sz + spacing) * 3.0f));
7283 ImGui::PopItemWidth();
7284 ImGui::EndTabItem();
7285 }
7286
7287 if (ImGui::BeginTabItem("Canvas"))
7288 {
7289 static ImVector<ImVec2> points;
7290 static ImVec2 scrolling(0.0f, 0.0f);
7291 static bool opt_enable_grid = true;
7292 static bool opt_enable_context_menu = true;
7293 static bool adding_line = false;
7294
7295 ImGui::Checkbox("Enable grid", &opt_enable_grid);
7296 ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
7297 ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
7298
7299 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
7300 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
7301 // To use a child window instead we could use, e.g:
7302 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
7303 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
7304 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove);
7305 // ImGui::PopStyleColor();
7306 // ImGui::PopStyleVar();
7307 // [...]
7308 // ImGui::EndChild();
7309
7310 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
7311 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
7312 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
7313 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
7314 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
7315 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
7316
7317 // Draw border and background color
7318 ImGuiIO& io = ImGui::GetIO();
7319 ImDrawList* draw_list = ImGui::GetWindowDrawList();
7320 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
7321 draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
7322
7323 // This will catch our interactions
7324 ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
7325 const bool is_hovered = ImGui::IsItemHovered(); // Hovered
7326 const bool is_active = ImGui::IsItemActive(); // Held
7327 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
7328 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
7329
7330 // Add first and second point
7331 if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
7332 {
7333 points.push_back(mouse_pos_in_canvas);
7334 points.push_back(mouse_pos_in_canvas);
7335 adding_line = true;
7336 }
7337 if (adding_line)
7338 {
7339 points.back() = mouse_pos_in_canvas;
7340 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
7341 adding_line = false;
7342 }
7343
7344 // Pan (we use a zero mouse threshold when there's no context menu)
7345 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
7346 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
7347 if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
7348 {
7349 scrolling.x += io.MouseDelta.x;
7350 scrolling.y += io.MouseDelta.y;
7351 }
7352
7353 // Context menu (under default mouse threshold)
7354 ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
7355 if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
7356 ImGui::OpenPopupOnItemClick("context");
7357 if (ImGui::BeginPopup("context"))
7358 {
7359 if (adding_line)
7360 points.resize(points.size() - 2);
7361 adding_line = false;
7362 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
7363 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
7364 ImGui::EndPopup();
7365 }
7366
7367 // Draw grid + all lines in the canvas
7368 draw_list->PushClipRect(canvas_p0, canvas_p1, true);
7369 if (opt_enable_grid)
7370 {
7371 const float GRID_STEP = 64.0f;
7372 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
7373 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));
7374 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
7375 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));
7376 }
7377 for (int n = 0; n < points.Size; n += 2)
7378 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);
7379 draw_list->PopClipRect();
7380
7381 ImGui::EndTabItem();
7382 }
7383
7384 if (ImGui::BeginTabItem("BG/FG draw lists"))
7385 {
7386 static bool draw_bg = true;
7387 static bool draw_fg = true;
7388 ImGui::Checkbox("Draw in Background draw list", &draw_bg);
7389 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
7390 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
7391 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
7392 ImVec2 window_pos = ImGui::GetWindowPos();
7393 ImVec2 window_size = ImGui::GetWindowSize();
7394 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
7395 if (draw_bg)
7396 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
7397 if (draw_fg)
7398 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
7399 ImGui::EndTabItem();
7400 }
7401
7402 ImGui::EndTabBar();
7403 }
7404
7405 ImGui::End();
7406 }
7407
7408 //-----------------------------------------------------------------------------
7409 // [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
7410 //-----------------------------------------------------------------------------
7411
7412 // Demonstrate using DockSpace() to create an explicit docking node within an existing window.
7413 // Note: You can use most Docking facilities without calling any API. You DO NOT need to call DockSpace() to use Docking!
7414 // - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.
7415 // - Drag from window menu button (upper-left button) to undock an entire node (all windows).
7416 // About dockspaces:
7417 // - Use DockSpace() to create an explicit dock node _within_ an existing window.
7418 // - Use DockSpaceOverViewport() to create an explicit dock node covering the screen or a specific viewport.
7419 // This is often used with ImGuiDockNodeFlags_PassthruCentralNode.
7420 // - Important: Dockspaces need to be submitted _before_ any window they can host. Submit it early in your frame! (*)
7421 // - Important: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked.
7422 // e.g. if you have multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly.
7423 // (*) because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node,
7424 // because that window is submitted as part of the part of the NewFrame() call. An easy workaround is that you can create
7425 // your own implicit "Debug##2" window after calling DockSpace() and leave it in the window stack for anyone to use.
7426 void ShowExampleAppDockSpace(bool* p_open)
7427 {
7428 // If you strip some features of, this demo is pretty much equivalent to calling DockSpaceOverViewport()!
7429 // In most cases you should be able to just call DockSpaceOverViewport() and ignore all the code below!
7430 // In this specific demo, we are not using DockSpaceOverViewport() because:
7431 // - we allow the host window to be floating/moveable instead of filling the viewport (when opt_fullscreen == false)
7432 // - we allow the host window to have padding (when opt_padding == true)
7433 // - we have a local menu bar in the host window (vs. you could use BeginMainMenuBar() + DockSpaceOverViewport() in your code!)
7434 // TL;DR; this demo is more complicated than what you would normally use.
7435 // If we removed all the options we are showcasing, this demo would become:
7436 // void ShowExampleAppDockSpace()
7437 // {
7438 // ImGui::DockSpaceOverViewport(ImGui::GetMainViewport());
7439 // }
7440
7441 static bool opt_fullscreen = true;
7442 static bool opt_padding = false;
7443 static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
7444
7445 // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
7446 // because it would be confusing to have two docking targets within each others.
7447 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
7448 if (opt_fullscreen)
7449 {
7450 const ImGuiViewport* viewport = ImGui::GetMainViewport();
7451 ImGui::SetNextWindowPos(viewport->WorkPos);
7452 ImGui::SetNextWindowSize(viewport->WorkSize);
7453 ImGui::SetNextWindowViewport(viewport->ID);
7454 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
7455 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
7456 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
7457 window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
7458 }
7459 else
7460 {
7461 dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
7462 }
7463
7464 // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
7465 // and handle the pass-thru hole, so we ask Begin() to not render a background.
7466 if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
7467 window_flags |= ImGuiWindowFlags_NoBackground;
7468
7469 // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
7470 // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
7471 // all active windows docked into it will lose their parent and become undocked.
7472 // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
7473 // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
7474 if (!opt_padding)
7475 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
7476 ImGui::Begin("DockSpace Demo", p_open, window_flags);
7477 if (!opt_padding)
7478 ImGui::PopStyleVar();
7479
7480 if (opt_fullscreen)
7481 ImGui::PopStyleVar(2);
7482
7483 // Submit the DockSpace
7484 ImGuiIO& io = ImGui::GetIO();
7485 if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
7486 {
7487 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
7488 ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
7489 }
7490 else
7491 {
7492 ShowDockingDisabledMessage();
7493 }
7494
7495 if (ImGui::BeginMenuBar())
7496 {
7497 if (ImGui::BeginMenu("Options"))
7498 {
7499 // Disabling fullscreen would allow the window to be moved to the front of other windows,
7500 // which we can't undo at the moment without finer window depth/z control.
7501 ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
7502 ImGui::MenuItem("Padding", NULL, &opt_padding);
7503 ImGui::Separator();
7504
7505 if (ImGui::MenuItem("Flag: NoSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoSplit) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoSplit; }
7506 if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoResize; }
7507 if (ImGui::MenuItem("Flag: NoDockingInCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode; }
7508 if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) { dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; }
7509 if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen)) { dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; }
7510 ImGui::Separator();
7511
7512 if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
7513 *p_open = false;
7514 ImGui::EndMenu();
7515 }
7516 HelpMarker(
7517 "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
7518 "- Drag from window title bar or their tab to dock/undock." "\n"
7519 "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
7520 "- Hold SHIFT to disable docking." "\n"
7521 "This demo app has nothing to do with it!" "\n\n"
7522 "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window." "\n\n"
7523 "Read comments in ShowExampleAppDockSpace() for more details.");
7524
7525 ImGui::EndMenuBar();
7526 }
7527
7528 ImGui::End();
7529 }
7530
7531 //-----------------------------------------------------------------------------
7532 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
7533 //-----------------------------------------------------------------------------
7534
7535 // Simplified structure to mimic a Document model
7536 struct MyDocument
7537 {
7538 const char* Name; // Document title
7539 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!)
7540 bool OpenPrev; // Copy of Open from last update.
7541 bool Dirty; // Set when the document has been modified
7542 bool WantClose; // Set when the document
7543 ImVec4 Color; // An arbitrary variable associated to the document
7544
7545 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
7546 {
7547 Name = name;
7548 Open = OpenPrev = open;
7549 Dirty = false;
7550 WantClose = false;
7551 Color = color;
7552 }
7553 void DoOpen() { Open = true; }
7554 void DoQueueClose() { WantClose = true; }
7555 void DoForceClose() { Open = false; Dirty = false; }
7556 void DoSave() { Dirty = false; }
7557
7558 // Display placeholder contents for the Document
7559 static void DisplayContents(MyDocument* doc)
7560 {
7561 ImGui::PushID(doc);
7562 ImGui::Text("Document \"%s\"", doc->Name);
7563 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
7564 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
7565 ImGui::PopStyleColor();
7566 if (ImGui::Button("Modify", ImVec2(100, 0)))
7567 doc->Dirty = true;
7568 ImGui::SameLine();
7569 if (ImGui::Button("Save", ImVec2(100, 0)))
7570 doc->DoSave();
7571 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
7572 ImGui::PopID();
7573 }
7574
7575 // Display context menu for the Document
7576 static void DisplayContextMenu(MyDocument* doc)
7577 {
7578 if (!ImGui::BeginPopupContextItem())
7579 return;
7580
7581 char buf[256];
7582 sprintf(buf, "Save %s", doc->Name);
7583 if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open))
7584 doc->DoSave();
7585 if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open))
7586 doc->DoQueueClose();
7587 ImGui::EndPopup();
7588 }
7589 };
7590
7591 struct ExampleAppDocuments
7592 {
7593 ImVector<MyDocument> Documents;
7594
7595 ExampleAppDocuments()
7596 {
7597 Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
7598 Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
7599 Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
7600 Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
7601 Documents.push_back(MyDocument("A Rather Long Title", false));
7602 Documents.push_back(MyDocument("Some Document", false));
7603 }
7604 };
7605
7606 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
7607 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
7608 // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
7609 // 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
7610 // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
7611 // give the impression of a flicker for one frame.
7612 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
7613 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
7614 static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
7615 {
7616 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7617 {
7618 MyDocument* doc = &app.Documents[doc_n];
7619 if (!doc->Open && doc->OpenPrev)
7620 ImGui::SetTabItemClosed(doc->Name);
7621 doc->OpenPrev = doc->Open;
7622 }
7623 }
7624
7625 void ShowExampleAppDocuments(bool* p_open)
7626 {
7627 static ExampleAppDocuments app;
7628
7629 // Options
7630 enum Target
7631 {
7632 Target_None,
7633 Target_Tab, // Create documents as local tab into a local tab bar
7634 Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace
7635 };
7636 static Target opt_target = Target_Tab;
7637 static bool opt_reorderable = true;
7638 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
7639
7640 // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant")
7641 // that we emit gets docked into the same spot as the parent window ("Example: Documents").
7642 // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab
7643 // not visible, which in turn would stop submitting the "Eggplant" window.
7644 // We avoid this problem by submitting our documents window even if our parent window is not currently visible.
7645 // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking.
7646
7647 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
7648 if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow)
7649 {
7650 ImGui::End();
7651 return;
7652 }
7653
7654 // Menu
7655 if (ImGui::BeginMenuBar())
7656 {
7657 if (ImGui::BeginMenu("File"))
7658 {
7659 int open_count = 0;
7660 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7661 open_count += app.Documents[doc_n].Open ? 1 : 0;
7662
7663 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
7664 {
7665 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7666 {
7667 MyDocument* doc = &app.Documents[doc_n];
7668 if (!doc->Open)
7669 if (ImGui::MenuItem(doc->Name))
7670 doc->DoOpen();
7671 }
7672 ImGui::EndMenu();
7673 }
7674 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
7675 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7676 app.Documents[doc_n].DoQueueClose();
7677 if (ImGui::MenuItem("Exit", "Alt+F4")) {}
7678 ImGui::EndMenu();
7679 }
7680 ImGui::EndMenuBar();
7681 }
7682
7683 // [Debug] List documents with one checkbox for each
7684 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7685 {
7686 MyDocument* doc = &app.Documents[doc_n];
7687 if (doc_n > 0)
7688 ImGui::SameLine();
7689 ImGui::PushID(doc);
7690 if (ImGui::Checkbox(doc->Name, &doc->Open))
7691 if (!doc->Open)
7692 doc->DoForceClose();
7693 ImGui::PopID();
7694 }
7695 ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
7696 ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
7697 ImGui::PopItemWidth();
7698 bool redock_all = false;
7699 if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
7700 if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
7701
7702 ImGui::Separator();
7703
7704 // About the ImGuiWindowFlags_UnsavedDocument / ImGuiTabItemFlags_UnsavedDocument flags.
7705 // They have multiple effects:
7706 // - Display a dot next to the title.
7707 // - Tab is selected when clicking the X close button.
7708 // - Closure is not assumed (will wait for user to stop submitting the tab).
7709 // Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
7710 // We need to assume closure by default otherwise waiting for "lack of submission" on the next frame would leave an empty
7711 // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window.
7712 // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole.
7713
7714 // Tabs
7715 if (opt_target == Target_Tab)
7716 {
7717 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
7718 if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
7719 {
7720 if (opt_reorderable)
7721 NotifyOfDocumentsClosedElsewhere(app);
7722
7723 // [DEBUG] Stress tests
7724 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
7725 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
7726
7727 // Submit Tabs
7728 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7729 {
7730 MyDocument* doc = &app.Documents[doc_n];
7731 if (!doc->Open)
7732 continue;
7733
7734 ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
7735 bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags);
7736
7737 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
7738 if (!doc->Open && doc->Dirty)
7739 {
7740 doc->Open = true;
7741 doc->DoQueueClose();
7742 }
7743
7744 MyDocument::DisplayContextMenu(doc);
7745 if (visible)
7746 {
7747 MyDocument::DisplayContents(doc);
7748 ImGui::EndTabItem();
7749 }
7750 }
7751
7752 ImGui::EndTabBar();
7753 }
7754 }
7755 else if (opt_target == Target_DockSpaceAndWindow)
7756 {
7757 if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
7758 {
7759 NotifyOfDocumentsClosedElsewhere(app);
7760
7761 // Create a DockSpace node where any window can be docked
7762 ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
7763 ImGui::DockSpace(dockspace_id);
7764
7765 // Create Windows
7766 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7767 {
7768 MyDocument* doc = &app.Documents[doc_n];
7769 if (!doc->Open)
7770 continue;
7771
7772 ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
7773 ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
7774 bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
7775
7776 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
7777 if (!doc->Open && doc->Dirty)
7778 {
7779 doc->Open = true;
7780 doc->DoQueueClose();
7781 }
7782
7783 MyDocument::DisplayContextMenu(doc);
7784 if (visible)
7785 MyDocument::DisplayContents(doc);
7786
7787 ImGui::End();
7788 }
7789 }
7790 else
7791 {
7792 ShowDockingDisabledMessage();
7793 }
7794 }
7795
7796 // Early out other contents
7797 if (!window_contents_visible)
7798 {
7799 ImGui::End();
7800 return;
7801 }
7802
7803 // Update closing queue
7804 static ImVector<MyDocument*> close_queue;
7805 if (close_queue.empty())
7806 {
7807 // Close queue is locked once we started a popup
7808 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
7809 {
7810 MyDocument* doc = &app.Documents[doc_n];
7811 if (doc->WantClose)
7812 {
7813 doc->WantClose = false;
7814 close_queue.push_back(doc);
7815 }
7816 }
7817 }
7818
7819 // Display closing confirmation UI
7820 if (!close_queue.empty())
7821 {
7822 int close_queue_unsaved_documents = 0;
7823 for (int n = 0; n < close_queue.Size; n++)
7824 if (close_queue[n]->Dirty)
7825 close_queue_unsaved_documents++;
7826
7827 if (close_queue_unsaved_documents == 0)
7828 {
7829 // Close documents when all are unsaved
7830 for (int n = 0; n < close_queue.Size; n++)
7831 close_queue[n]->DoForceClose();
7832 close_queue.clear();
7833 }
7834 else
7835 {
7836 if (!ImGui::IsPopupOpen("Save?"))
7837 ImGui::OpenPopup("Save?");
7838 if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
7839 {
7840 ImGui::Text("Save change to the following items?");
7841 float item_height = ImGui::GetTextLineHeightWithSpacing();
7842 if (ImGui::BeginChildFrame(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height)))
7843 {
7844 for (int n = 0; n < close_queue.Size; n++)
7845 if (close_queue[n]->Dirty)
7846 ImGui::Text("%s", close_queue[n]->Name);
7847 ImGui::EndChildFrame();
7848 }
7849
7850 ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f);
7851 if (ImGui::Button("Yes", button_size))
7852 {
7853 for (int n = 0; n < close_queue.Size; n++)
7854 {
7855 if (close_queue[n]->Dirty)
7856 close_queue[n]->DoSave();
7857 close_queue[n]->DoForceClose();
7858 }
7859 close_queue.clear();
7860 ImGui::CloseCurrentPopup();
7861 }
7862 ImGui::SameLine();
7863 if (ImGui::Button("No", button_size))
7864 {
7865 for (int n = 0; n < close_queue.Size; n++)
7866 close_queue[n]->DoForceClose();
7867 close_queue.clear();
7868 ImGui::CloseCurrentPopup();
7869 }
7870 ImGui::SameLine();
7871 if (ImGui::Button("Cancel", button_size))
7872 {
7873 close_queue.clear();
7874 ImGui::CloseCurrentPopup();
7875 }
7876 ImGui::EndPopup();
7877 }
7878 }
7879 }
7880
7881 ImGui::End();
7882 }
7883
7884 // End of Demo code
7885 #else
7886
7887 void ImGui::ShowAboutWindow(bool*) {}
7888 void ImGui::ShowDemoWindow(bool*) {}
7889 void ImGui::ShowUserGuide() {}
7890 void ImGui::ShowStyleEditor(ImGuiStyle*) {}
7891
7892 #endif
7893
7894 #endif // #ifndef IMGUI_DISABLE
7895