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