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