8618a9ee728502bb5fc61ef055b6fde3685a07af
[mesa.git] / src / imgui / imgui_demo.cpp
1 // dear imgui, v1.68 WIP
2 // (demo code)
3
4 // Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
5 // Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other coders
6 // will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of
7 // your game/app! Removing this file from your project is hindering access to documentation for everyone in your team,
8 // likely leading you to poorer usage of the library.
9 // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
10 // If you want to link core Dear ImGui in your shipped builds but want an easy guarantee that the demo will not be linked,
11 // you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
12 // In other situation, whenever you have Dear ImGui available you probably want this to be available for reference.
13 // Thank you,
14 // -Your beloved friend, imgui_demo.cpp (that you won't delete)
15
16 // Message to beginner C/C++ programmers about the meaning of the 'static' keyword:
17 // In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is
18 // essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data
19 // in the same place, to make the demo source code faster to read, faster to write, and smaller in size.
20 // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant
21 // or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is
22 // likely going to be stored outside your functions.
23
24 /*
25
26 Index of this file:
27
28 // [SECTION] Forward Declarations, Helpers
29 // [SECTION] Demo Window / ShowDemoWindow()
30 // [SECTION] About Window / ShowAboutWindow()
31 // [SECTION] Style Editor / ShowStyleEditor()
32 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
33 // [SECTION] Example App: Debug Console / ShowExampleAppConsole()
34 // [SECTION] Example App: Debug Log / ShowExampleAppLog()
35 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
36 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
37 // [SECTION] Example App: Long Text / ShowExampleAppLongText()
38 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
39 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
40 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
41 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
42 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
43 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
44
45 */
46
47 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
48 #define _CRT_SECURE_NO_WARNINGS
49 #endif
50
51 #include "imgui.h"
52 #include <ctype.h> // toupper, isprint
53 #include <limits.h> // INT_MIN, INT_MAX
54 #include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
55 #include <stdio.h> // vsnprintf, sscanf, printf
56 #include <stdlib.h> // NULL, malloc, free, atoi
57 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
58 #include <stddef.h> // intptr_t
59 #else
60 #include <stdint.h> // intptr_t
61 #endif
62
63 #ifdef _MSC_VER
64 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
65 #endif
66 #ifdef __clang__
67 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
68 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code)
69 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
70 #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal
71 #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.
72 #pragma clang diagnostic ignored "-Wunused-macros" // warning : warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used.
73 #if __has_warning("-Wzero-as-null-pointer-constant")
74 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
75 #endif
76 #if __has_warning("-Wdouble-promotion")
77 #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.
78 #endif
79 #if __has_warning("-Wreserved-id-macro")
80 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
81 #endif
82 #elif defined(__GNUC__)
83 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
84 #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure)
85 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
86 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
87 #if (__GNUC__ >= 6)
88 #pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub.
89 #endif
90 #endif
91
92 // Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n.
93 #ifdef _WIN32
94 #define IM_NEWLINE "\r\n"
95 #define snprintf _snprintf
96 #define vsnprintf _vsnprintf
97 #else
98 #define IM_NEWLINE "\n"
99 #endif
100
101 #define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B))
102
103 //-----------------------------------------------------------------------------
104 // [SECTION] Forward Declarations, Helpers
105 //-----------------------------------------------------------------------------
106
107 #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Obsolete name since 1.53, TEST->DEMO
108 #define IMGUI_DISABLE_DEMO_WINDOWS
109 #endif
110
111 #if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
112
113 // Forward Declarations
114 static void ShowExampleAppDocuments(bool* p_open);
115 static void ShowExampleAppMainMenuBar();
116 static void ShowExampleAppConsole(bool* p_open);
117 static void ShowExampleAppLog(bool* p_open);
118 static void ShowExampleAppLayout(bool* p_open);
119 static void ShowExampleAppPropertyEditor(bool* p_open);
120 static void ShowExampleAppLongText(bool* p_open);
121 static void ShowExampleAppAutoResize(bool* p_open);
122 static void ShowExampleAppConstrainedResize(bool* p_open);
123 static void ShowExampleAppSimpleOverlay(bool* p_open);
124 static void ShowExampleAppWindowTitles(bool* p_open);
125 static void ShowExampleAppCustomRendering(bool* p_open);
126 static void ShowExampleMenuFile();
127
128 // Helper to display a little (?) mark which shows a tooltip when hovered.
129 static void ShowHelpMarker(const char* desc)
130 {
131 ImGui::TextDisabled("(?)");
132 if (ImGui::IsItemHovered())
133 {
134 ImGui::BeginTooltip();
135 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
136 ImGui::TextUnformatted(desc);
137 ImGui::PopTextWrapPos();
138 ImGui::EndTooltip();
139 }
140 }
141
142 // Helper to display basic user controls.
143 void ImGui::ShowUserGuide()
144 {
145 ImGui::BulletText("Double-click on title bar to collapse window.");
146 ImGui::BulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents).");
147 ImGui::BulletText("Click and drag on any empty space to move window.");
148 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
149 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
150 if (ImGui::GetIO().FontAllowUserScaling)
151 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
152 ImGui::BulletText("Mouse Wheel to scroll.");
153 ImGui::BulletText("While editing text:\n");
154 ImGui::Indent();
155 ImGui::BulletText("Hold SHIFT or use mouse to select text.");
156 ImGui::BulletText("CTRL+Left/Right to word jump.");
157 ImGui::BulletText("CTRL+A or double-click to select all.");
158 ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard.");
159 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
160 ImGui::BulletText("ESCAPE to revert.");
161 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
162 ImGui::Unindent();
163 }
164
165 //-----------------------------------------------------------------------------
166 // [SECTION] Demo Window / ShowDemoWindow()
167 //-----------------------------------------------------------------------------
168
169 // We split the contents of the big ShowDemoWindow() function into smaller functions (because the link time of very large functions grow non-linearly)
170 static void ShowDemoWindowWidgets();
171 static void ShowDemoWindowLayout();
172 static void ShowDemoWindowPopups();
173 static void ShowDemoWindowColumns();
174 static void ShowDemoWindowMisc();
175
176 // Demonstrate most Dear ImGui features (this is big function!)
177 // You may execute this function to experiment with the UI and understand what it does. You may then search for keywords in the code when you are interested by a specific feature.
178 void ImGui::ShowDemoWindow(bool* p_open)
179 {
180 // Examples Apps (accessible from the "Examples" menu)
181 static bool show_app_documents = false;
182 static bool show_app_main_menu_bar = false;
183 static bool show_app_console = false;
184 static bool show_app_log = false;
185 static bool show_app_layout = false;
186 static bool show_app_property_editor = false;
187 static bool show_app_long_text = false;
188 static bool show_app_auto_resize = false;
189 static bool show_app_constrained_resize = false;
190 static bool show_app_simple_overlay = false;
191 static bool show_app_window_titles = false;
192 static bool show_app_custom_rendering = false;
193
194 if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
195 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
196 if (show_app_console) ShowExampleAppConsole(&show_app_console);
197 if (show_app_log) ShowExampleAppLog(&show_app_log);
198 if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
199 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
200 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
201 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
202 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
203 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
204 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
205 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
206
207 // Dear ImGui Apps (accessible from the "Help" menu)
208 static bool show_app_metrics = false;
209 static bool show_app_style_editor = false;
210 static bool show_app_about = false;
211
212 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); }
213 if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); }
214 if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); }
215
216 // Demonstrate the various window flags. Typically you would just use the default!
217 static bool no_titlebar = false;
218 static bool no_scrollbar = false;
219 static bool no_menu = false;
220 static bool no_move = false;
221 static bool no_resize = false;
222 static bool no_collapse = false;
223 static bool no_close = false;
224 static bool no_nav = false;
225 static bool no_background = false;
226 static bool no_bring_to_front = false;
227
228 ImGuiWindowFlags window_flags = 0;
229 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
230 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
231 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
232 if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
233 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
234 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
235 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
236 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground;
237 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
238 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
239
240 // We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming.
241 ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver);
242 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
243
244 // Main body of the Demo window starts here.
245 if (!ImGui::Begin("ImGui Demo", p_open, window_flags))
246 {
247 // Early out if the window is collapsed, as an optimization.
248 ImGui::End();
249 return;
250 }
251 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION);
252
253 // Most "big" widgets share a common width settings by default.
254 //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // Use 2/3 of the space for widgets and 1/3 for labels (default)
255 ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // Use fixed width for labels (by passing a negative value), the rest goes to widgets. We choose a width proportional to our font size.
256
257 // Menu
258 if (ImGui::BeginMenuBar())
259 {
260 if (ImGui::BeginMenu("Menu"))
261 {
262 ShowExampleMenuFile();
263 ImGui::EndMenu();
264 }
265 if (ImGui::BeginMenu("Examples"))
266 {
267 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
268 ImGui::MenuItem("Console", NULL, &show_app_console);
269 ImGui::MenuItem("Log", NULL, &show_app_log);
270 ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
271 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
272 ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
273 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
274 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
275 ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
276 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
277 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
278 ImGui::MenuItem("Documents", NULL, &show_app_documents);
279 ImGui::EndMenu();
280 }
281 if (ImGui::BeginMenu("Help"))
282 {
283 ImGui::MenuItem("Metrics", NULL, &show_app_metrics);
284 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
285 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
286 ImGui::EndMenu();
287 }
288 ImGui::EndMenuBar();
289 }
290
291 ImGui::Spacing();
292 if (ImGui::CollapsingHeader("Help"))
293 {
294 ImGui::Text("PROGRAMMER GUIDE:");
295 ImGui::BulletText("Please see the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
296 ImGui::BulletText("Please see the comments in imgui.cpp.");
297 ImGui::BulletText("Please see the examples/ in application.");
298 ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
299 ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
300 ImGui::Separator();
301
302 ImGui::Text("USER GUIDE:");
303 ImGui::ShowUserGuide();
304 }
305
306 if (ImGui::CollapsingHeader("Configuration"))
307 {
308 ImGuiIO& io = ImGui::GetIO();
309
310 if (ImGui::TreeNode("Configuration##2"))
311 {
312 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
313 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
314 ImGui::SameLine(); ShowHelpMarker("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.");
315 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
316 ImGui::SameLine(); ShowHelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
317 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouse);
318 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) // Create a way to restore this flag otherwise we could be stuck completely!
319 {
320 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
321 {
322 ImGui::SameLine();
323 ImGui::Text("<<PRESS SPACE TO DISABLE>>");
324 }
325 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space)))
326 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
327 }
328 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
329 ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility.");
330 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
331 ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting");
332 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
333 ImGui::SameLine(); ShowHelpMarker("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.");
334 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
335 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
336 ImGui::SameLine(); ShowHelpMarker("Instruct Dear ImGui to render a mouse cursor for you. 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).");
337 ImGui::TreePop();
338 ImGui::Separator();
339 }
340
341 if (ImGui::TreeNode("Backend Flags"))
342 {
343 ShowHelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.");
344 ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying the back-end flags.
345 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad);
346 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors);
347 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasSetMousePos);
348 ImGui::TreePop();
349 ImGui::Separator();
350 }
351
352 if (ImGui::TreeNode("Style"))
353 {
354 ImGui::ShowStyleEditor();
355 ImGui::TreePop();
356 ImGui::Separator();
357 }
358
359 if (ImGui::TreeNode("Capture/Logging"))
360 {
361 ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded.");
362 ShowHelpMarker("Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
363 ImGui::LogButtons();
364 ImGui::TextWrapped("You can also call ImGui::LogText() to output directly to the log without a visual output.");
365 if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
366 {
367 ImGui::LogToClipboard();
368 ImGui::LogText("Hello, world!");
369 ImGui::LogFinish();
370 }
371 ImGui::TreePop();
372 }
373 }
374
375 if (ImGui::CollapsingHeader("Window options"))
376 {
377 ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150);
378 ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300);
379 ImGui::Checkbox("No menu", &no_menu);
380 ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150);
381 ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300);
382 ImGui::Checkbox("No collapse", &no_collapse);
383 ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150);
384 ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300);
385 ImGui::Checkbox("No background", &no_background);
386 ImGui::Checkbox("No bring to front", &no_bring_to_front);
387 }
388
389 // All demo contents
390 ShowDemoWindowWidgets();
391 ShowDemoWindowLayout();
392 ShowDemoWindowPopups();
393 ShowDemoWindowColumns();
394 ShowDemoWindowMisc();
395
396 // End of ShowDemoWindow()
397 ImGui::End();
398 }
399
400 static void ShowDemoWindowWidgets()
401 {
402 if (!ImGui::CollapsingHeader("Widgets"))
403 return;
404
405 if (ImGui::TreeNode("Basic"))
406 {
407 static int clicked = 0;
408 if (ImGui::Button("Button"))
409 clicked++;
410 if (clicked & 1)
411 {
412 ImGui::SameLine();
413 ImGui::Text("Thanks for clicking me!");
414 }
415
416 static bool check = true;
417 ImGui::Checkbox("checkbox", &check);
418
419 static int e = 0;
420 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
421 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
422 ImGui::RadioButton("radio c", &e, 2);
423
424 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
425 for (int i = 0; i < 7; i++)
426 {
427 if (i > 0)
428 ImGui::SameLine();
429 ImGui::PushID(i);
430 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f));
431 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.7f));
432 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i/7.0f, 0.8f, 0.8f));
433 ImGui::Button("Click");
434 ImGui::PopStyleColor(3);
435 ImGui::PopID();
436 }
437
438 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default)
439 ImGui::AlignTextToFramePadding();
440 ImGui::Text("Hold to repeat:");
441 ImGui::SameLine();
442
443 // Arrow buttons with Repeater
444 static int counter = 0;
445 float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
446 ImGui::PushButtonRepeat(true);
447 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
448 ImGui::SameLine(0.0f, spacing);
449 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
450 ImGui::PopButtonRepeat();
451 ImGui::SameLine();
452 ImGui::Text("%d", counter);
453
454 ImGui::Text("Hover over me");
455 if (ImGui::IsItemHovered())
456 ImGui::SetTooltip("I am a tooltip");
457
458 ImGui::SameLine();
459 ImGui::Text("- or me");
460 if (ImGui::IsItemHovered())
461 {
462 ImGui::BeginTooltip();
463 ImGui::Text("I am a fancy tooltip");
464 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
465 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
466 ImGui::EndTooltip();
467 }
468
469 ImGui::Separator();
470
471 ImGui::LabelText("label", "Value");
472
473 {
474 // Using the _simplified_ one-liner Combo() api here
475 // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api.
476 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
477 static int item_current = 0;
478 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
479 ImGui::SameLine(); ShowHelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n");
480 }
481
482 {
483 static char str0[128] = "Hello, world!";
484 static int i0 = 123;
485 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
486 ImGui::SameLine(); ShowHelpMarker("USER:\nHold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n\nPROGRAMMER:\nYou can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated in imgui_demo.cpp).");
487
488 ImGui::InputInt("input int", &i0);
489 ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n");
490
491 static float f0 = 0.001f;
492 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
493
494 static double d0 = 999999.00000001;
495 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
496
497 static float f1 = 1.e10f;
498 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
499 ImGui::SameLine(); ShowHelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".\n");
500
501 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
502 ImGui::InputFloat3("input float3", vec4a);
503 }
504
505 {
506 static int i1 = 50, i2 = 42;
507 ImGui::DragInt("drag int", &i1, 1);
508 ImGui::SameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value.");
509
510 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%");
511
512 static float f1=1.00f, f2=0.0067f;
513 ImGui::DragFloat("drag float", &f1, 0.005f);
514 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
515 }
516
517 {
518 static int i1=0;
519 ImGui::SliderInt("slider int", &i1, -1, 3);
520 ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value.");
521
522 static float f1=0.123f, f2=0.0f;
523 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
524 ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f);
525 static float angle = 0.0f;
526 ImGui::SliderAngle("slider angle", &angle);
527 }
528
529 {
530 static float col1[3] = { 1.0f,0.0f,0.2f };
531 static float col2[4] = { 0.4f,0.7f,0.0f,0.5f };
532 ImGui::ColorEdit3("color 1", col1);
533 ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nClick and hold to use drag and drop.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n");
534
535 ImGui::ColorEdit4("color 2", col2);
536 }
537
538 {
539 // List box
540 const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
541 static int listbox_item_current = 1;
542 ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
543
544 //static int listbox_item_current2 = 2;
545 //ImGui::PushItemWidth(-1);
546 //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
547 //ImGui::PopItemWidth();
548 }
549
550 ImGui::TreePop();
551 }
552
553 // Testing ImGuiOnceUponAFrame helper.
554 //static ImGuiOnceUponAFrame once;
555 //for (int i = 0; i < 5; i++)
556 // if (once)
557 // ImGui::Text("This will be displayed only once.");
558
559 if (ImGui::TreeNode("Trees"))
560 {
561 if (ImGui::TreeNode("Basic trees"))
562 {
563 for (int i = 0; i < 5; i++)
564 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
565 {
566 ImGui::Text("blah blah");
567 ImGui::SameLine();
568 if (ImGui::SmallButton("button")) { };
569 ImGui::TreePop();
570 }
571 ImGui::TreePop();
572 }
573
574 if (ImGui::TreeNode("Advanced, with Selectable nodes"))
575 {
576 ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open.");
577 static bool align_label_with_current_x_position = false;
578 ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position);
579 ImGui::Text("Hello!");
580 if (align_label_with_current_x_position)
581 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
582
583 static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit.
584 int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc.
585 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents.
586 for (int i = 0; i < 6; i++)
587 {
588 // Disable the default open on single-click behavior and pass in Selected flag according to our selection state.
589 ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0);
590 if (i < 3)
591 {
592 // Node
593 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
594 if (ImGui::IsItemClicked())
595 node_clicked = i;
596 if (node_open)
597 {
598 ImGui::Text("Blah blah\nBlah Blah");
599 ImGui::TreePop();
600 }
601 }
602 else
603 {
604 // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text().
605 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
606 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
607 if (ImGui::IsItemClicked())
608 node_clicked = i;
609 }
610 }
611 if (node_clicked != -1)
612 {
613 // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.
614 if (ImGui::GetIO().KeyCtrl)
615 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
616 else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection
617 selection_mask = (1 << node_clicked); // Click to single-select
618 }
619 ImGui::PopStyleVar();
620 if (align_label_with_current_x_position)
621 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
622 ImGui::TreePop();
623 }
624 ImGui::TreePop();
625 }
626
627 if (ImGui::TreeNode("Collapsing Headers"))
628 {
629 static bool closable_group = true;
630 ImGui::Checkbox("Enable extra group", &closable_group);
631 if (ImGui::CollapsingHeader("Header"))
632 {
633 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
634 for (int i = 0; i < 5; i++)
635 ImGui::Text("Some content %d", i);
636 }
637 if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
638 {
639 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
640 for (int i = 0; i < 5; i++)
641 ImGui::Text("More content %d", i);
642 }
643 ImGui::TreePop();
644 }
645
646 if (ImGui::TreeNode("Bullets"))
647 {
648 ImGui::BulletText("Bullet point 1");
649 ImGui::BulletText("Bullet point 2\nOn multiple lines");
650 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
651 ImGui::Bullet(); ImGui::SmallButton("Button");
652 ImGui::TreePop();
653 }
654
655 if (ImGui::TreeNode("Text"))
656 {
657 if (ImGui::TreeNode("Colored Text"))
658 {
659 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
660 ImGui::TextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink");
661 ImGui::TextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow");
662 ImGui::TextDisabled("Disabled");
663 ImGui::SameLine(); ShowHelpMarker("The TextDisabled color is stored in ImGuiStyle.");
664 ImGui::TreePop();
665 }
666
667 if (ImGui::TreeNode("Word Wrapping"))
668 {
669 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
670 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.");
671 ImGui::Spacing();
672
673 static float wrap_width = 200.0f;
674 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
675
676 ImGui::Text("Test paragraph 1:");
677 ImVec2 pos = ImGui::GetCursorScreenPos();
678 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255));
679 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
680 ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width);
681 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255));
682 ImGui::PopTextWrapPos();
683
684 ImGui::Text("Test paragraph 2:");
685 pos = ImGui::GetCursorScreenPos();
686 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255,0,255,255));
687 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
688 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
689 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,255,0,255));
690 ImGui::PopTextWrapPos();
691
692 ImGui::TreePop();
693 }
694
695 if (ImGui::TreeNode("UTF-8 Text"))
696 {
697 // UTF-8 test with Japanese characters
698 // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read misc/fonts/README.txt for details.)
699 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
700 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature')
701 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE.
702 // Instead we are encoding a few strings with hexadecimal constants. Don't do this in your application!
703 // Please use u8"text in any language" in your application!
704 // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application.
705 ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read misc/fonts/README.txt for details.");
706 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.
707 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
708 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
709 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
710 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
711 ImGui::TreePop();
712 }
713 ImGui::TreePop();
714 }
715
716 if (ImGui::TreeNode("Images"))
717 {
718 ImGuiIO& io = ImGui::GetIO();
719 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!");
720
721 // Here we are grabbing the font texture because that's the only one we have access to inside the demo code.
722 // Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure.
723 // If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID.
724 // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_glfw_gl3.cpp renderer expect a GLuint OpenGL texture identifier etc.)
725 // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc.
726 // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this.
727 // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
728 ImTextureID my_tex_id = io.Fonts->TexID;
729 float my_tex_w = (float)io.Fonts->TexWidth;
730 float my_tex_h = (float)io.Fonts->TexHeight;
731
732 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
733 ImVec2 pos = ImGui::GetCursorScreenPos();
734 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128));
735 if (ImGui::IsItemHovered())
736 {
737 ImGui::BeginTooltip();
738 float region_sz = 32.0f;
739 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; if (region_x < 0.0f) region_x = 0.0f; else if (region_x > my_tex_w - region_sz) region_x = my_tex_w - region_sz;
740 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; if (region_y < 0.0f) region_y = 0.0f; else if (region_y > my_tex_h - region_sz) region_y = my_tex_h - region_sz;
741 float zoom = 4.0f;
742 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
743 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
744 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
745 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
746 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImColor(255,255,255,255), ImColor(255,255,255,128));
747 ImGui::EndTooltip();
748 }
749 ImGui::TextWrapped("And now some textured buttons..");
750 static int pressed_count = 0;
751 for (int i = 0; i < 8; i++)
752 {
753 ImGui::PushID(i);
754 int frame_padding = -1 + i; // -1 = uses default padding
755 if (ImGui::ImageButton(my_tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/my_tex_w,32/my_tex_h), frame_padding, ImColor(0,0,0,255)))
756 pressed_count += 1;
757 ImGui::PopID();
758 ImGui::SameLine();
759 }
760 ImGui::NewLine();
761 ImGui::Text("Pressed %d times.", pressed_count);
762 ImGui::TreePop();
763 }
764
765 if (ImGui::TreeNode("Combo"))
766 {
767 // Expose flags as checkbox for the demo
768 static ImGuiComboFlags flags = 0;
769 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft);
770 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton))
771 flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both
772 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview))
773 flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both
774
775 // General BeginCombo() API, you have full control over your selection data and display type.
776 // (your selection data could be an index, a pointer to the object, an id for the object, a flag stored in the object itself, etc.)
777 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
778 static const char* item_current = items[0]; // Here our selection is a single pointer stored outside the object.
779 if (ImGui::BeginCombo("combo 1", item_current, flags)) // The second parameter is the label previewed before opening the combo.
780 {
781 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
782 {
783 bool is_selected = (item_current == items[n]);
784 if (ImGui::Selectable(items[n], is_selected))
785 item_current = items[n];
786 if (is_selected)
787 ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
788 }
789 ImGui::EndCombo();
790 }
791
792 // Simplified one-liner Combo() API, using values packed in a single constant string
793 static int item_current_2 = 0;
794 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
795
796 // Simplified one-liner Combo() using an array of const char*
797 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
798 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
799
800 // Simplified one-liner Combo() using an accessor function
801 struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } };
802 static int item_current_4 = 0;
803 ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items));
804
805 ImGui::TreePop();
806 }
807
808 if (ImGui::TreeNode("Selectables"))
809 {
810 // Selectable() has 2 overloads:
811 // - The one taking "bool selected" as a read-only selection information. When Selectable() has been clicked is returns true and you can alter selection state accordingly.
812 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
813 // The earlier is more flexible, as in real application your selection may be stored in a different manner (in flags within objects, as an external list, etc).
814 if (ImGui::TreeNode("Basic"))
815 {
816 static bool selection[5] = { false, true, false, false, false };
817 ImGui::Selectable("1. I am selectable", &selection[0]);
818 ImGui::Selectable("2. I am selectable", &selection[1]);
819 ImGui::Text("3. I am not selectable");
820 ImGui::Selectable("4. I am selectable", &selection[3]);
821 if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick))
822 if (ImGui::IsMouseDoubleClicked(0))
823 selection[4] = !selection[4];
824 ImGui::TreePop();
825 }
826 if (ImGui::TreeNode("Selection State: Single Selection"))
827 {
828 static int selected = -1;
829 for (int n = 0; n < 5; n++)
830 {
831 char buf[32];
832 sprintf(buf, "Object %d", n);
833 if (ImGui::Selectable(buf, selected == n))
834 selected = n;
835 }
836 ImGui::TreePop();
837 }
838 if (ImGui::TreeNode("Selection State: Multiple Selection"))
839 {
840 ShowHelpMarker("Hold CTRL and click to select multiple items.");
841 static bool selection[5] = { false, false, false, false, false };
842 for (int n = 0; n < 5; n++)
843 {
844 char buf[32];
845 sprintf(buf, "Object %d", n);
846 if (ImGui::Selectable(buf, selection[n]))
847 {
848 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
849 memset(selection, 0, sizeof(selection));
850 selection[n] ^= 1;
851 }
852 }
853 ImGui::TreePop();
854 }
855 if (ImGui::TreeNode("Rendering more text into the same line"))
856 {
857 // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically.
858 static bool selected[3] = { false, false, false };
859 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
860 ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes");
861 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
862 ImGui::TreePop();
863 }
864 if (ImGui::TreeNode("In columns"))
865 {
866 ImGui::Columns(3, NULL, false);
867 static bool selected[16] = { 0 };
868 for (int i = 0; i < 16; i++)
869 {
870 char label[32]; sprintf(label, "Item %d", i);
871 if (ImGui::Selectable(label, &selected[i])) {}
872 ImGui::NextColumn();
873 }
874 ImGui::Columns(1);
875 ImGui::TreePop();
876 }
877 if (ImGui::TreeNode("Grid"))
878 {
879 static bool selected[4*4] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true };
880 for (int i = 0; i < 4*4; i++)
881 {
882 ImGui::PushID(i);
883 if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50,50)))
884 {
885 // Note: We _unnecessarily_ test for both x/y and i here only to silence some static analyzer. The second part of each test is unnecessary.
886 int x = i % 4;
887 int y = i / 4;
888 if (x > 0) { selected[i - 1] ^= 1; }
889 if (x < 3 && i < 15) { selected[i + 1] ^= 1; }
890 if (y > 0 && i > 3) { selected[i - 4] ^= 1; }
891 if (y < 3 && i < 12) { selected[i + 4] ^= 1; }
892 }
893 if ((i % 4) < 3) ImGui::SameLine();
894 ImGui::PopID();
895 }
896 ImGui::TreePop();
897 }
898 if (ImGui::TreeNode("Alignment"))
899 {
900 ShowHelpMarker("Alignment applies when a selectable is larger than its text content.\nBy default, Selectables uses style.SelectableTextAlign but it can be overriden on a per-item basis using PushStyleVar().");
901 static bool selected[3*3] = { true, false, true, false, true, false, true, false, true };
902 for (int y = 0; y < 3; y++)
903 {
904 for (int x = 0; x < 3; x++)
905 {
906 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
907 char name[32];
908 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
909 if (x > 0) ImGui::SameLine();
910 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
911 ImGui::Selectable(name, &selected[3*y+x], ImGuiSelectableFlags_None, ImVec2(80,80));
912 ImGui::PopStyleVar();
913 }
914 }
915 ImGui::TreePop();
916 }
917 ImGui::TreePop();
918 }
919
920 if (ImGui::TreeNode("Filtered Text Input"))
921 {
922 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64);
923 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal);
924 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
925 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase);
926 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank);
927 struct TextFilters { static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } };
928 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters);
929
930 ImGui::Text("Password input");
931 static char bufpass[64] = "password123";
932 ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank);
933 ImGui::SameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
934 ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank);
935
936 ImGui::TreePop();
937 }
938
939 if (ImGui::TreeNode("Multi-line Text Input"))
940 {
941 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
942 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
943 static bool read_only = false;
944 static char text[1024*16] =
945 "/*\n"
946 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
947 " the hexadecimal encoding of one offending instruction,\n"
948 " more formally, the invalid operand with locked CMPXCHG8B\n"
949 " instruction bug, is a design flaw in the majority of\n"
950 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
951 " processors (all in the P5 microarchitecture).\n"
952 "*/\n\n"
953 "label:\n"
954 "\tlock cmpxchg8b eax\n";
955
956 ShowHelpMarker("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)");
957 ImGui::Checkbox("Read-only", &read_only);
958 ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0);
959 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), flags);
960 ImGui::TreePop();
961 }
962
963 if (ImGui::TreeNode("Plots Widgets"))
964 {
965 static bool animate = true;
966 ImGui::Checkbox("Animate", &animate);
967
968 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
969 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
970
971 // Create a dummy array of contiguous float values to plot
972 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter.
973 static float values[90] = { 0 };
974 static int values_offset = 0;
975 static double refresh_time = 0.0;
976 if (!animate || refresh_time == 0.0)
977 refresh_time = ImGui::GetTime();
978 while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo
979 {
980 static float phase = 0.0f;
981 values[values_offset] = cosf(phase);
982 values_offset = (values_offset+1) % IM_ARRAYSIZE(values);
983 phase += 0.10f*values_offset;
984 refresh_time += 1.0f/60.0f;
985 }
986 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80));
987 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80));
988
989 // Use functions to generate output
990 // FIXME: This is rather awkward because current plot API only pass in indices. We probably want an API passing floats and user provide sample rate/count.
991 struct Funcs
992 {
993 static float Sin(void*, int i) { return sinf(i * 0.1f); }
994 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
995 };
996 static int func_type = 0, display_count = 70;
997 ImGui::Separator();
998 ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth();
999 ImGui::SameLine();
1000 ImGui::SliderInt("Sample count", &display_count, 1, 400);
1001 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
1002 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80));
1003 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0,80));
1004 ImGui::Separator();
1005
1006 // Animate a simple progress bar
1007 static float progress = 0.0f, progress_dir = 1.0f;
1008 if (animate)
1009 {
1010 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
1011 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
1012 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
1013 }
1014
1015 // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
1016 ImGui::ProgressBar(progress, ImVec2(0.0f,0.0f));
1017 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
1018 ImGui::Text("Progress Bar");
1019
1020 float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress;
1021 char buf[32];
1022 sprintf(buf, "%d/%d", (int)(progress_saturated*1753), 1753);
1023 ImGui::ProgressBar(progress, ImVec2(0.f,0.f), buf);
1024 ImGui::TreePop();
1025 }
1026
1027 if (ImGui::TreeNode("Color/Picker Widgets"))
1028 {
1029 static ImVec4 color = ImVec4(114.0f/255.0f, 144.0f/255.0f, 154.0f/255.0f, 200.0f/255.0f);
1030
1031 static bool alpha_preview = true;
1032 static bool alpha_half_preview = false;
1033 static bool drag_and_drop = true;
1034 static bool options_menu = true;
1035 static bool hdr = false;
1036 ImGui::Checkbox("With Alpha Preview", &alpha_preview);
1037 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
1038 ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
1039 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); ShowHelpMarker("Right-click on the individual color widget to show options.");
1040 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); ShowHelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
1041 int 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);
1042
1043 ImGui::Text("Color widget:");
1044 ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n");
1045 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
1046
1047 ImGui::Text("Color widget HSV with Alpha:");
1048 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_HSV | misc_flags);
1049
1050 ImGui::Text("Color widget with Float Display:");
1051 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
1052
1053 ImGui::Text("Color button with Picker:");
1054 ImGui::SameLine(); ShowHelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup.");
1055 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
1056
1057 ImGui::Text("Color button with Custom Picker Popup:");
1058
1059 // Generate a dummy default palette. The palette will persist and can be edited.
1060 static bool saved_palette_init = true;
1061 static ImVec4 saved_palette[32] = { };
1062 if (saved_palette_init)
1063 {
1064 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
1065 {
1066 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
1067 saved_palette[n].w = 1.0f; // Alpha
1068 }
1069 saved_palette_init = false;
1070 }
1071
1072 static ImVec4 backup_color;
1073 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
1074 ImGui::SameLine();
1075 open_popup |= ImGui::Button("Palette");
1076 if (open_popup)
1077 {
1078 ImGui::OpenPopup("mypicker");
1079 backup_color = color;
1080 }
1081 if (ImGui::BeginPopup("mypicker"))
1082 {
1083 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
1084 ImGui::Separator();
1085 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
1086 ImGui::SameLine();
1087
1088 ImGui::BeginGroup(); // Lock X position
1089 ImGui::Text("Current");
1090 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40));
1091 ImGui::Text("Previous");
1092 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)))
1093 color = backup_color;
1094 ImGui::Separator();
1095 ImGui::Text("Palette");
1096 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
1097 {
1098 ImGui::PushID(n);
1099 if ((n % 8) != 0)
1100 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
1101 if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20)))
1102 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
1103
1104 // Allow user to drop colors into each palette entry
1105 // (Note that ColorButton is already a drag source by default, unless using ImGuiColorEditFlags_NoDragDrop)
1106 if (ImGui::BeginDragDropTarget())
1107 {
1108 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
1109 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
1110 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
1111 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
1112 ImGui::EndDragDropTarget();
1113 }
1114
1115 ImGui::PopID();
1116 }
1117 ImGui::EndGroup();
1118 ImGui::EndPopup();
1119 }
1120
1121 ImGui::Text("Color button only:");
1122 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags, ImVec2(80,80));
1123
1124 ImGui::Text("Color picker:");
1125 static bool alpha = true;
1126 static bool alpha_bar = true;
1127 static bool side_preview = true;
1128 static bool ref_color = false;
1129 static ImVec4 ref_color_v(1.0f,0.0f,1.0f,0.5f);
1130 static int inputs_mode = 2;
1131 static int picker_mode = 0;
1132 ImGui::Checkbox("With Alpha", &alpha);
1133 ImGui::Checkbox("With Alpha Bar", &alpha_bar);
1134 ImGui::Checkbox("With Side Preview", &side_preview);
1135 if (side_preview)
1136 {
1137 ImGui::SameLine();
1138 ImGui::Checkbox("With Ref Color", &ref_color);
1139 if (ref_color)
1140 {
1141 ImGui::SameLine();
1142 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
1143 }
1144 }
1145 ImGui::Combo("Inputs Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0");
1146 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
1147 ImGui::SameLine(); ShowHelpMarker("User can right-click the picker to change mode.");
1148 ImGuiColorEditFlags flags = misc_flags;
1149 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
1150 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
1151 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
1152 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
1153 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
1154 if (inputs_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;
1155 if (inputs_mode == 2) flags |= ImGuiColorEditFlags_RGB;
1156 if (inputs_mode == 3) flags |= ImGuiColorEditFlags_HSV;
1157 if (inputs_mode == 4) flags |= ImGuiColorEditFlags_HEX;
1158 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
1159
1160 ImGui::Text("Programmatically set defaults:");
1161 ImGui::SameLine(); ShowHelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible.");
1162 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
1163 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_HSV | ImGuiColorEditFlags_PickerHueBar);
1164 if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
1165 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
1166
1167 ImGui::TreePop();
1168 }
1169
1170 if (ImGui::TreeNode("Range Widgets"))
1171 {
1172 static float begin = 10, end = 90;
1173 static int begin_i = 100, end_i = 1000;
1174 ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%");
1175 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
1176 ImGui::TreePop();
1177 }
1178
1179 if (ImGui::TreeNode("Data Types"))
1180 {
1181 // The DragScalar/InputScalar/SliderScalar functions allow various data types: signed/unsigned int/long long and float/double
1182 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum to pass the type,
1183 // and passing all arguments by address.
1184 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types.
1185 // In practice, if you frequently use a given type that is not covered by the normal API entry points, you can wrap it
1186 // yourself inside a 1 line function which can take typed argument as value instead of void*, and then pass their address
1187 // to the generic function. For example:
1188 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
1189 // {
1190 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
1191 // }
1192
1193 // Limits (as helper variables that we can take the address of)
1194 // Note that the SliderScalar function has a maximum usable range of half the natural type maximum, hence the /2 below.
1195 #ifndef LLONG_MIN
1196 ImS64 LLONG_MIN = -9223372036854775807LL - 1;
1197 ImS64 LLONG_MAX = 9223372036854775807LL;
1198 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
1199 #endif
1200 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;
1201 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;
1202 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;
1203 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;
1204 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
1205 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
1206
1207 // State
1208 static ImS32 s32_v = -1;
1209 static ImU32 u32_v = (ImU32)-1;
1210 static ImS64 s64_v = -1;
1211 static ImU64 u64_v = (ImU64)-1;
1212 static float f32_v = 0.123f;
1213 static double f64_v = 90000.01234567890123456789;
1214
1215 const float drag_speed = 0.2f;
1216 static bool drag_clamp = false;
1217 ImGui::Text("Drags:");
1218 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); ShowHelpMarker("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.");
1219 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
1220 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
1221 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
1222 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
1223 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 1.0f);
1224 ImGui::DragScalar("drag float ^2", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", 2.0f); ImGui::SameLine(); ShowHelpMarker("You can use the 'power' parameter to increase tweaking precision on one side of the range.");
1225 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams", 1.0f);
1226 ImGui::DragScalar("drag double ^2", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", 2.0f);
1227
1228 ImGui::Text("Sliders");
1229 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d");
1230 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d");
1231 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d");
1232 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
1233 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
1234 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
1235 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d");
1236 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d");
1237 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d");
1238 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms");
1239 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms");
1240 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms");
1241 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
1242 ImGui::SliderScalar("slider float low^2", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", 2.0f);
1243 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
1244 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams", 1.0f);
1245 ImGui::SliderScalar("slider double low^2",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", 2.0f);
1246 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams", 1.0f);
1247
1248 static bool inputs_step = true;
1249 ImGui::Text("Inputs");
1250 ImGui::Checkbox("Show step buttons", &inputs_step);
1251 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
1252 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
1253 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
1254 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
1255 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL);
1256 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL);
1257 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL);
1258 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL);
1259
1260 ImGui::TreePop();
1261 }
1262
1263 if (ImGui::TreeNode("Multi-component Widgets"))
1264 {
1265 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
1266 static int vec4i[4] = { 1, 5, 100, 255 };
1267
1268 ImGui::InputFloat2("input float2", vec4f);
1269 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
1270 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
1271 ImGui::InputInt2("input int2", vec4i);
1272 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
1273 ImGui::SliderInt2("slider int2", vec4i, 0, 255);
1274 ImGui::Spacing();
1275
1276 ImGui::InputFloat3("input float3", vec4f);
1277 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
1278 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
1279 ImGui::InputInt3("input int3", vec4i);
1280 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
1281 ImGui::SliderInt3("slider int3", vec4i, 0, 255);
1282 ImGui::Spacing();
1283
1284 ImGui::InputFloat4("input float4", vec4f);
1285 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
1286 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
1287 ImGui::InputInt4("input int4", vec4i);
1288 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
1289 ImGui::SliderInt4("slider int4", vec4i, 0, 255);
1290
1291 ImGui::TreePop();
1292 }
1293
1294 if (ImGui::TreeNode("Vertical Sliders"))
1295 {
1296 const float spacing = 4;
1297 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1298
1299 static int int_value = 0;
1300 ImGui::VSliderInt("##int", ImVec2(18,160), &int_value, 0, 5);
1301 ImGui::SameLine();
1302
1303 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
1304 ImGui::PushID("set1");
1305 for (int i = 0; i < 7; i++)
1306 {
1307 if (i > 0) ImGui::SameLine();
1308 ImGui::PushID(i);
1309 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i/7.0f, 0.5f, 0.5f));
1310 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.5f));
1311 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.5f));
1312 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i/7.0f, 0.9f, 0.9f));
1313 ImGui::VSliderFloat("##v", ImVec2(18,160), &values[i], 0.0f, 1.0f, "");
1314 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
1315 ImGui::SetTooltip("%.3f", values[i]);
1316 ImGui::PopStyleColor(4);
1317 ImGui::PopID();
1318 }
1319 ImGui::PopID();
1320
1321 ImGui::SameLine();
1322 ImGui::PushID("set2");
1323 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
1324 const int rows = 3;
1325 const ImVec2 small_slider_size(18, (160.0f-(rows-1)*spacing)/rows);
1326 for (int nx = 0; nx < 4; nx++)
1327 {
1328 if (nx > 0) ImGui::SameLine();
1329 ImGui::BeginGroup();
1330 for (int ny = 0; ny < rows; ny++)
1331 {
1332 ImGui::PushID(nx*rows+ny);
1333 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
1334 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
1335 ImGui::SetTooltip("%.3f", values2[nx]);
1336 ImGui::PopID();
1337 }
1338 ImGui::EndGroup();
1339 }
1340 ImGui::PopID();
1341
1342 ImGui::SameLine();
1343 ImGui::PushID("set3");
1344 for (int i = 0; i < 4; i++)
1345 {
1346 if (i > 0) ImGui::SameLine();
1347 ImGui::PushID(i);
1348 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
1349 ImGui::VSliderFloat("##v", ImVec2(40,160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
1350 ImGui::PopStyleVar();
1351 ImGui::PopID();
1352 }
1353 ImGui::PopID();
1354 ImGui::PopStyleVar();
1355 ImGui::TreePop();
1356 }
1357
1358 if (ImGui::TreeNode("Drag and Drop"))
1359 {
1360 {
1361 // ColorEdit widgets automatically act as drag source and drag target.
1362 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F to allow your own widgets
1363 // to use colors in their drag and drop interaction. Also see the demo in Color Picker -> Palette demo.
1364 ImGui::BulletText("Drag and drop in standard widgets");
1365 ImGui::Indent();
1366 static float col1[3] = { 1.0f,0.0f,0.2f };
1367 static float col2[4] = { 0.4f,0.7f,0.0f,0.5f };
1368 ImGui::ColorEdit3("color 1", col1);
1369 ImGui::ColorEdit4("color 2", col2);
1370 ImGui::Unindent();
1371 }
1372
1373 {
1374 ImGui::BulletText("Drag and drop to copy/swap items");
1375 ImGui::Indent();
1376 enum Mode
1377 {
1378 Mode_Copy,
1379 Mode_Move,
1380 Mode_Swap
1381 };
1382 static int mode = 0;
1383 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
1384 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
1385 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
1386 static const char* names[9] = { "Bobby", "Beatrice", "Betty", "Brianna", "Barry", "Bernard", "Bibi", "Blaine", "Bryn" };
1387 for (int n = 0; n < IM_ARRAYSIZE(names); n++)
1388 {
1389 ImGui::PushID(n);
1390 if ((n % 3) != 0)
1391 ImGui::SameLine();
1392 ImGui::Button(names[n], ImVec2(60,60));
1393
1394 // Our buttons are both drag sources and drag targets here!
1395 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
1396 {
1397 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); // Set payload to carry the index of our item (could be anything)
1398 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } // Display preview (could be anything, e.g. when dragging an image we could decide to display the filename and a small preview of the image, etc.)
1399 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
1400 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
1401 ImGui::EndDragDropSource();
1402 }
1403 if (ImGui::BeginDragDropTarget())
1404 {
1405 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
1406 {
1407 IM_ASSERT(payload->DataSize == sizeof(int));
1408 int payload_n = *(const int*)payload->Data;
1409 if (mode == Mode_Copy)
1410 {
1411 names[n] = names[payload_n];
1412 }
1413 if (mode == Mode_Move)
1414 {
1415 names[n] = names[payload_n];
1416 names[payload_n] = "";
1417 }
1418 if (mode == Mode_Swap)
1419 {
1420 const char* tmp = names[n];
1421 names[n] = names[payload_n];
1422 names[payload_n] = tmp;
1423 }
1424 }
1425 ImGui::EndDragDropTarget();
1426 }
1427 ImGui::PopID();
1428 }
1429 ImGui::Unindent();
1430 }
1431
1432 ImGui::TreePop();
1433 }
1434
1435 if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)"))
1436 {
1437 // Display the value of IsItemHovered() and other common item state functions. Note that the flags can be combined.
1438 // (because BulletText is an item itself and that would affect the output of IsItemHovered() we pass all state in a single call to simplify the code).
1439 static int item_type = 1;
1440 static bool b = false;
1441 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
1442 ImGui::RadioButton("Text", &item_type, 0);
1443 ImGui::RadioButton("Button", &item_type, 1);
1444 ImGui::RadioButton("Checkbox", &item_type, 2);
1445 ImGui::RadioButton("SliderFloat", &item_type, 3);
1446 ImGui::RadioButton("ColorEdit4", &item_type, 4);
1447 ImGui::RadioButton("ListBox", &item_type, 5);
1448 ImGui::Separator();
1449 bool ret = false;
1450 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
1451 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
1452 if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
1453 if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
1454 if (item_type == 4) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
1455 if (item_type == 5) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
1456 ImGui::BulletText(
1457 "Return value = %d\n"
1458 "IsItemFocused() = %d\n"
1459 "IsItemHovered() = %d\n"
1460 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
1461 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
1462 "IsItemHovered(_AllowWhenOverlapped) = %d\n"
1463 "IsItemHovered(_RectOnly) = %d\n"
1464 "IsItemActive() = %d\n"
1465 "IsItemEdited() = %d\n"
1466 "IsItemActivated() = %d\n"
1467 "IsItemDeactivated() = %d\n"
1468 "IsItemDeactivatedEdit() = %d\n"
1469 "IsItemVisible() = %d\n"
1470 "GetItemRectMin() = (%.1f, %.1f)\n"
1471 "GetItemRectMax() = (%.1f, %.1f)\n"
1472 "GetItemRectSize() = (%.1f, %.1f)",
1473 ret,
1474 ImGui::IsItemFocused(),
1475 ImGui::IsItemHovered(),
1476 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
1477 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
1478 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped),
1479 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
1480 ImGui::IsItemActive(),
1481 ImGui::IsItemEdited(),
1482 ImGui::IsItemActivated(),
1483 ImGui::IsItemDeactivated(),
1484 ImGui::IsItemDeactivatedAfterEdit(),
1485 ImGui::IsItemVisible(),
1486 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
1487 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
1488 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
1489 );
1490
1491 static bool embed_all_inside_a_child_window = false;
1492 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window);
1493 if (embed_all_inside_a_child_window)
1494 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20), true);
1495
1496 // Testing IsWindowFocused() function with its various flags. Note that the flags can be combined.
1497 ImGui::BulletText(
1498 "IsWindowFocused() = %d\n"
1499 "IsWindowFocused(_ChildWindows) = %d\n"
1500 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
1501 "IsWindowFocused(_RootWindow) = %d\n"
1502 "IsWindowFocused(_AnyWindow) = %d\n",
1503 ImGui::IsWindowFocused(),
1504 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
1505 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
1506 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
1507 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
1508
1509 // Testing IsWindowHovered() function with its various flags. Note that the flags can be combined.
1510 ImGui::BulletText(
1511 "IsWindowHovered() = %d\n"
1512 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
1513 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
1514 "IsWindowHovered(_ChildWindows) = %d\n"
1515 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
1516 "IsWindowHovered(_RootWindow) = %d\n"
1517 "IsWindowHovered(_AnyWindow) = %d\n",
1518 ImGui::IsWindowHovered(),
1519 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
1520 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
1521 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
1522 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
1523 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
1524 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));
1525
1526 ImGui::BeginChild("child", ImVec2(0, 50), true);
1527 ImGui::Text("This is another child window for testing the _ChildWindows flag.");
1528 ImGui::EndChild();
1529 if (embed_all_inside_a_child_window)
1530 ImGui::EndChild();
1531
1532 // Calling IsItemHovered() after begin returns the hovered status of the title bar.
1533 // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window.
1534 static bool test_window = false;
1535 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
1536 if (test_window)
1537 {
1538 ImGui::Begin("Title bar Hovered/Active tests", &test_window);
1539 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
1540 {
1541 if (ImGui::MenuItem("Close")) { test_window = false; }
1542 ImGui::EndPopup();
1543 }
1544 ImGui::Text(
1545 "IsItemHovered() after begin = %d (== is title bar hovered)\n"
1546 "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
1547 ImGui::IsItemHovered(), ImGui::IsItemActive());
1548 ImGui::End();
1549 }
1550
1551 ImGui::TreePop();
1552 }
1553 }
1554
1555 static void ShowDemoWindowLayout()
1556 {
1557 if (!ImGui::CollapsingHeader("Layout"))
1558 return;
1559
1560 if (ImGui::TreeNode("Child windows"))
1561 {
1562 ShowHelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
1563 static bool disable_mouse_wheel = false;
1564 static bool disable_menu = false;
1565 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
1566 ImGui::Checkbox("Disable Menu", &disable_menu);
1567
1568 static int line = 50;
1569 bool goto_line = ImGui::Button("Goto");
1570 ImGui::SameLine();
1571 ImGui::PushItemWidth(100);
1572 goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue);
1573 ImGui::PopItemWidth();
1574
1575 // Child 1: no border, enable horizontal scrollbar
1576 {
1577 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0);
1578 ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags);
1579 for (int i = 0; i < 100; i++)
1580 {
1581 ImGui::Text("%04d: scrollable region", i);
1582 if (goto_line && line == i)
1583 ImGui::SetScrollHereY();
1584 }
1585 if (goto_line && line >= 100)
1586 ImGui::SetScrollHereY();
1587 ImGui::EndChild();
1588 }
1589
1590 ImGui::SameLine();
1591
1592 // Child 2: rounded border
1593 {
1594 ImGuiWindowFlags window_flags = (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar);
1595 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
1596 ImGui::BeginChild("Child2", ImVec2(0, 260), true, window_flags);
1597 if (!disable_menu && ImGui::BeginMenuBar())
1598 {
1599 if (ImGui::BeginMenu("Menu"))
1600 {
1601 ShowExampleMenuFile();
1602 ImGui::EndMenu();
1603 }
1604 ImGui::EndMenuBar();
1605 }
1606 ImGui::Columns(2);
1607 for (int i = 0; i < 100; i++)
1608 {
1609 char buf[32];
1610 sprintf(buf, "%03d", i);
1611 ImGui::Button(buf, ImVec2(-1.0f, 0.0f));
1612 ImGui::NextColumn();
1613 }
1614 ImGui::EndChild();
1615 ImGui::PopStyleVar();
1616 }
1617
1618 ImGui::Separator();
1619
1620 // Demonstrate a few extra things
1621 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
1622 // - Using SetCursorPos() to position the child window (because the child window is an item from the POV of the parent window)
1623 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively layout from this position.
1624 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window)
1625 // See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this.
1626 {
1627 ImGui::SetCursorPosX(50);
1628 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
1629 ImGui::BeginChild("blah", ImVec2(200, 100), true, ImGuiWindowFlags_None);
1630 for (int n = 0; n < 50; n++)
1631 ImGui::Text("Some test %d", n);
1632 ImGui::EndChild();
1633 ImVec2 child_rect_min = ImGui::GetItemRectMin();
1634 ImVec2 child_rect_max = ImGui::GetItemRectMax();
1635 ImGui::PopStyleColor();
1636 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);
1637 }
1638
1639 ImGui::TreePop();
1640 }
1641
1642 if (ImGui::TreeNode("Widgets Width"))
1643 {
1644 static float f = 0.0f;
1645 ImGui::Text("PushItemWidth(100)");
1646 ImGui::SameLine(); ShowHelpMarker("Fixed width.");
1647 ImGui::PushItemWidth(100);
1648 ImGui::DragFloat("float##1", &f);
1649 ImGui::PopItemWidth();
1650
1651 ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f)");
1652 ImGui::SameLine(); ShowHelpMarker("Half of window width.");
1653 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
1654 ImGui::DragFloat("float##2", &f);
1655 ImGui::PopItemWidth();
1656
1657 ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)");
1658 ImGui::SameLine(); ShowHelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
1659 ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f);
1660 ImGui::DragFloat("float##3", &f);
1661 ImGui::PopItemWidth();
1662
1663 ImGui::Text("PushItemWidth(-100)");
1664 ImGui::SameLine(); ShowHelpMarker("Align to right edge minus 100");
1665 ImGui::PushItemWidth(-100);
1666 ImGui::DragFloat("float##4", &f);
1667 ImGui::PopItemWidth();
1668
1669 ImGui::Text("PushItemWidth(-1)");
1670 ImGui::SameLine(); ShowHelpMarker("Align to right edge");
1671 ImGui::PushItemWidth(-1);
1672 ImGui::DragFloat("float##5", &f);
1673 ImGui::PopItemWidth();
1674
1675 ImGui::TreePop();
1676 }
1677
1678 if (ImGui::TreeNode("Basic Horizontal Layout"))
1679 {
1680 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
1681
1682 // Text
1683 ImGui::Text("Two items: Hello"); ImGui::SameLine();
1684 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
1685
1686 // Adjust spacing
1687 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
1688 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
1689
1690 // Button
1691 ImGui::AlignTextToFramePadding();
1692 ImGui::Text("Normal buttons"); ImGui::SameLine();
1693 ImGui::Button("Banana"); ImGui::SameLine();
1694 ImGui::Button("Apple"); ImGui::SameLine();
1695 ImGui::Button("Corniflower");
1696
1697 // Button
1698 ImGui::Text("Small buttons"); ImGui::SameLine();
1699 ImGui::SmallButton("Like this one"); ImGui::SameLine();
1700 ImGui::Text("can fit within a text block.");
1701
1702 // Aligned to arbitrary position. Easy/cheap column.
1703 ImGui::Text("Aligned");
1704 ImGui::SameLine(150); ImGui::Text("x=150");
1705 ImGui::SameLine(300); ImGui::Text("x=300");
1706 ImGui::Text("Aligned");
1707 ImGui::SameLine(150); ImGui::SmallButton("x=150");
1708 ImGui::SameLine(300); ImGui::SmallButton("x=300");
1709
1710 // Checkbox
1711 static bool c1 = false, c2 = false, c3 = false, c4 = false;
1712 ImGui::Checkbox("My", &c1); ImGui::SameLine();
1713 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
1714 ImGui::Checkbox("Is", &c3); ImGui::SameLine();
1715 ImGui::Checkbox("Rich", &c4);
1716
1717 // Various
1718 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
1719 ImGui::PushItemWidth(80);
1720 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
1721 static int item = -1;
1722 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
1723 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
1724 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
1725 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
1726 ImGui::PopItemWidth();
1727
1728 ImGui::PushItemWidth(80);
1729 ImGui::Text("Lists:");
1730 static int selection[4] = { 0, 1, 2, 3 };
1731 for (int i = 0; i < 4; i++)
1732 {
1733 if (i > 0) ImGui::SameLine();
1734 ImGui::PushID(i);
1735 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
1736 ImGui::PopID();
1737 //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i);
1738 }
1739 ImGui::PopItemWidth();
1740
1741 // Dummy
1742 ImVec2 button_sz(40, 40);
1743 ImGui::Button("A", button_sz); ImGui::SameLine();
1744 ImGui::Dummy(button_sz); ImGui::SameLine();
1745 ImGui::Button("B", button_sz);
1746
1747 // Manually wrapping (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
1748 ImGui::Text("Manually wrapping:");
1749 ImGuiStyle& style = ImGui::GetStyle();
1750 int buttons_count = 20;
1751 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
1752 for (int n = 0; n < buttons_count; n++)
1753 {
1754 ImGui::PushID(n);
1755 ImGui::Button("Box", button_sz);
1756 float last_button_x2 = ImGui::GetItemRectMax().x;
1757 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
1758 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
1759 ImGui::SameLine();
1760 ImGui::PopID();
1761 }
1762
1763 ImGui::TreePop();
1764 }
1765
1766 if (ImGui::TreeNode("Tabs"))
1767 {
1768 if (ImGui::TreeNode("Basic"))
1769 {
1770 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
1771 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1772 {
1773 if (ImGui::BeginTabItem("Avocado"))
1774 {
1775 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
1776 ImGui::EndTabItem();
1777 }
1778 if (ImGui::BeginTabItem("Broccoli"))
1779 {
1780 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
1781 ImGui::EndTabItem();
1782 }
1783 if (ImGui::BeginTabItem("Cucumber"))
1784 {
1785 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
1786 ImGui::EndTabItem();
1787 }
1788 ImGui::EndTabBar();
1789 }
1790 ImGui::Separator();
1791 ImGui::TreePop();
1792 }
1793
1794 if (ImGui::TreeNode("Advanced & Close Button"))
1795 {
1796 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
1797 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
1798 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable);
1799 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
1800 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
1801 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
1802 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
1803 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
1804 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
1805 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
1806 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
1807 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
1808
1809 // Tab Bar
1810 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
1811 static bool opened[4] = { true, true, true, true }; // Persistent user state
1812 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1813 {
1814 if (n > 0) { ImGui::SameLine(); }
1815 ImGui::Checkbox(names[n], &opened[n]);
1816 }
1817
1818 // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): the underlying bool will be set to false when the tab is closed.
1819 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
1820 {
1821 for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
1822 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n]))
1823 {
1824 ImGui::Text("This is the %s tab!", names[n]);
1825 if (n & 1)
1826 ImGui::Text("I am an odd tab.");
1827 ImGui::EndTabItem();
1828 }
1829 ImGui::EndTabBar();
1830 }
1831 ImGui::Separator();
1832 ImGui::TreePop();
1833 }
1834 ImGui::TreePop();
1835 }
1836
1837 if (ImGui::TreeNode("Groups"))
1838 {
1839 ShowHelpMarker("Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.");
1840 ImGui::BeginGroup();
1841 {
1842 ImGui::BeginGroup();
1843 ImGui::Button("AAA");
1844 ImGui::SameLine();
1845 ImGui::Button("BBB");
1846 ImGui::SameLine();
1847 ImGui::BeginGroup();
1848 ImGui::Button("CCC");
1849 ImGui::Button("DDD");
1850 ImGui::EndGroup();
1851 ImGui::SameLine();
1852 ImGui::Button("EEE");
1853 ImGui::EndGroup();
1854 if (ImGui::IsItemHovered())
1855 ImGui::SetTooltip("First group hovered");
1856 }
1857 // Capture the group size and create widgets using the same size
1858 ImVec2 size = ImGui::GetItemRectSize();
1859 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
1860 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
1861
1862 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));
1863 ImGui::SameLine();
1864 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));
1865 ImGui::EndGroup();
1866 ImGui::SameLine();
1867
1868 ImGui::Button("LEVERAGE\nBUZZWORD", size);
1869 ImGui::SameLine();
1870
1871 if (ImGui::ListBoxHeader("List", size))
1872 {
1873 ImGui::Selectable("Selected", true);
1874 ImGui::Selectable("Not Selected", false);
1875 ImGui::ListBoxFooter();
1876 }
1877
1878 ImGui::TreePop();
1879 }
1880
1881 if (ImGui::TreeNode("Text Baseline Alignment"))
1882 {
1883 ShowHelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets.");
1884
1885 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
1886 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
1887 ImGui::Text("Banana");
1888
1889 ImGui::Text("Banana"); ImGui::SameLine();
1890 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
1891 ImGui::Text("One\nTwo\nThree");
1892
1893 ImGui::Button("HOP##1"); ImGui::SameLine();
1894 ImGui::Text("Banana"); ImGui::SameLine();
1895 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
1896 ImGui::Text("Banana");
1897
1898 ImGui::Button("HOP##2"); ImGui::SameLine();
1899 ImGui::Text("Hello\nWorld"); ImGui::SameLine();
1900 ImGui::Text("Banana");
1901
1902 ImGui::Button("TEST##1"); ImGui::SameLine();
1903 ImGui::Text("TEST"); ImGui::SameLine();
1904 ImGui::SmallButton("TEST##2");
1905
1906 ImGui::AlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets.
1907 ImGui::Text("Text aligned to Widget"); ImGui::SameLine();
1908 ImGui::Button("Widget##1"); ImGui::SameLine();
1909 ImGui::Text("Widget"); ImGui::SameLine();
1910 ImGui::SmallButton("Widget##2"); ImGui::SameLine();
1911 ImGui::Button("Widget##3");
1912
1913 // Tree
1914 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
1915 ImGui::Button("Button##1");
1916 ImGui::SameLine(0.0f, spacing);
1917 if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data
1918
1919 ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit).
1920 bool node_open = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content.
1921 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
1922 if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data
1923
1924 // Bullet
1925 ImGui::Button("Button##3");
1926 ImGui::SameLine(0.0f, spacing);
1927 ImGui::BulletText("Bullet text");
1928
1929 ImGui::AlignTextToFramePadding();
1930 ImGui::BulletText("Node");
1931 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
1932
1933 ImGui::TreePop();
1934 }
1935
1936 if (ImGui::TreeNode("Scrolling"))
1937 {
1938 ShowHelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position.");
1939
1940 static bool track = true;
1941 static int track_line = 50, scroll_to_px = 200;
1942 ImGui::Checkbox("Track", &track);
1943 ImGui::PushItemWidth(100);
1944 ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d");
1945 bool scroll_to = ImGui::Button("Scroll To Pos");
1946 ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %d px");
1947 ImGui::PopItemWidth();
1948 if (scroll_to) track = false;
1949
1950 for (int i = 0; i < 5; i++)
1951 {
1952 if (i > 0) ImGui::SameLine();
1953 ImGui::BeginGroup();
1954 ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom");
1955 ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true);
1956 if (scroll_to)
1957 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f);
1958 for (int line = 0; line < 100; line++)
1959 {
1960 if (track && line == track_line)
1961 {
1962 ImGui::TextColored(ImVec4(1,1,0,1), "Line %d", line);
1963 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
1964 }
1965 else
1966 {
1967 ImGui::Text("Line %d", line);
1968 }
1969 }
1970 float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY();
1971 ImGui::EndChild();
1972 ImGui::Text("%.0f/%0.f", scroll_y, scroll_max_y);
1973 ImGui::EndGroup();
1974 }
1975 ImGui::TreePop();
1976 }
1977
1978 if (ImGui::TreeNode("Horizontal Scrolling"))
1979 {
1980 ShowHelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin().");
1981 static int lines = 7;
1982 ImGui::SliderInt("Lines", &lines, 1, 15);
1983 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
1984 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
1985 ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar);
1986 for (int line = 0; line < lines; line++)
1987 {
1988 // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off
1989 // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API)
1990 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
1991 for (int n = 0; n < num_buttons; n++)
1992 {
1993 if (n > 0) ImGui::SameLine();
1994 ImGui::PushID(n + line * 1000);
1995 char num_buf[16];
1996 sprintf(num_buf, "%d", n);
1997 const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : num_buf;
1998 float hue = n*0.05f;
1999 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
2000 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
2001 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
2002 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
2003 ImGui::PopStyleColor(3);
2004 ImGui::PopID();
2005 }
2006 }
2007 float scroll_x = ImGui::GetScrollX(), scroll_max_x = ImGui::GetScrollMaxX();
2008 ImGui::EndChild();
2009 ImGui::PopStyleVar(2);
2010 float scroll_x_delta = 0.0f;
2011 ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) { scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine();
2012 ImGui::Text("Scroll from code"); ImGui::SameLine();
2013 ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) { scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; } ImGui::SameLine();
2014 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
2015 if (scroll_x_delta != 0.0f)
2016 {
2017 ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window)
2018 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
2019 ImGui::EndChild();
2020 }
2021 ImGui::TreePop();
2022 }
2023
2024 if (ImGui::TreeNode("Clipping"))
2025 {
2026 static ImVec2 size(100, 100), offset(50, 20);
2027 ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost.");
2028 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
2029 ImGui::TextWrapped("(Click and drag)");
2030 ImVec2 pos = ImGui::GetCursorScreenPos();
2031 ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y);
2032 ImGui::InvisibleButton("##dummy", size);
2033 if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; }
2034 ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255));
2035 ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32(255, 255, 255, 255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect);
2036 ImGui::TreePop();
2037 }
2038 }
2039
2040 static void ShowDemoWindowPopups()
2041 {
2042 if (!ImGui::CollapsingHeader("Popups & Modal windows"))
2043 return;
2044
2045 // The properties of popups windows are:
2046 // - They block normal mouse hovering detection outside them. (*)
2047 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
2048 // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls.
2049 // User can manipulate the visibility state by calling OpenPopup().
2050 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
2051 // Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time.
2052
2053 // Typical use for regular windows:
2054 // 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();
2055 // Typical use for popups:
2056 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
2057
2058 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
2059 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
2060
2061 if (ImGui::TreeNode("Popups"))
2062 {
2063 ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it.");
2064
2065 static int selected_fish = -1;
2066 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
2067 static bool toggles[] = { true, false, false, false, false };
2068
2069 // Simple selection popup
2070 // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
2071 if (ImGui::Button("Select.."))
2072 ImGui::OpenPopup("my_select_popup");
2073 ImGui::SameLine();
2074 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
2075 if (ImGui::BeginPopup("my_select_popup"))
2076 {
2077 ImGui::Text("Aquarium");
2078 ImGui::Separator();
2079 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
2080 if (ImGui::Selectable(names[i]))
2081 selected_fish = i;
2082 ImGui::EndPopup();
2083 }
2084
2085 // Showing a menu with toggles
2086 if (ImGui::Button("Toggle.."))
2087 ImGui::OpenPopup("my_toggle_popup");
2088 if (ImGui::BeginPopup("my_toggle_popup"))
2089 {
2090 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
2091 ImGui::MenuItem(names[i], "", &toggles[i]);
2092 if (ImGui::BeginMenu("Sub-menu"))
2093 {
2094 ImGui::MenuItem("Click me");
2095 ImGui::EndMenu();
2096 }
2097
2098 ImGui::Separator();
2099 ImGui::Text("Tooltip here");
2100 if (ImGui::IsItemHovered())
2101 ImGui::SetTooltip("I am a tooltip over a popup");
2102
2103 if (ImGui::Button("Stacked Popup"))
2104 ImGui::OpenPopup("another popup");
2105 if (ImGui::BeginPopup("another popup"))
2106 {
2107 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
2108 ImGui::MenuItem(names[i], "", &toggles[i]);
2109 if (ImGui::BeginMenu("Sub-menu"))
2110 {
2111 ImGui::MenuItem("Click me");
2112 ImGui::EndMenu();
2113 }
2114 ImGui::EndPopup();
2115 }
2116 ImGui::EndPopup();
2117 }
2118
2119 // Call the more complete ShowExampleMenuFile which we use in various places of this demo
2120 if (ImGui::Button("File Menu.."))
2121 ImGui::OpenPopup("my_file_popup");
2122 if (ImGui::BeginPopup("my_file_popup"))
2123 {
2124 ShowExampleMenuFile();
2125 ImGui::EndPopup();
2126 }
2127
2128 ImGui::TreePop();
2129 }
2130
2131 if (ImGui::TreeNode("Context menus"))
2132 {
2133 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
2134 // if (IsItemHovered() && IsMouseReleased(0))
2135 // OpenPopup(id);
2136 // return BeginPopup(id);
2137 // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation.
2138 static float value = 0.5f;
2139 ImGui::Text("Value = %.3f (<-- right-click here)", value);
2140 if (ImGui::BeginPopupContextItem("item context menu"))
2141 {
2142 if (ImGui::Selectable("Set to zero")) value = 0.0f;
2143 if (ImGui::Selectable("Set to PI")) value = 3.1415f;
2144 ImGui::PushItemWidth(-1);
2145 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
2146 ImGui::PopItemWidth();
2147 ImGui::EndPopup();
2148 }
2149
2150 // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the Begin call.
2151 // So here we will make it that clicking on the text field with the right mouse button (1) will toggle the visibility of the popup above.
2152 ImGui::Text("(You can also right-click me to the same popup as above.)");
2153 ImGui::OpenPopupOnItemClick("item context menu", 1);
2154
2155 // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem().
2156 // BeginPopupContextItem() will use the last item ID as the popup ID.
2157 // In addition here, we want to include your editable label inside the button label. We use the ### operator to override the ID (read FAQ about ID for details)
2158 static char name[32] = "Label1";
2159 char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
2160 ImGui::Button(buf);
2161 if (ImGui::BeginPopupContextItem())
2162 {
2163 ImGui::Text("Edit name:");
2164 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
2165 if (ImGui::Button("Close"))
2166 ImGui::CloseCurrentPopup();
2167 ImGui::EndPopup();
2168 }
2169 ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
2170
2171 ImGui::TreePop();
2172 }
2173
2174 if (ImGui::TreeNode("Modals"))
2175 {
2176 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window.");
2177
2178 if (ImGui::Button("Delete.."))
2179 ImGui::OpenPopup("Delete?");
2180
2181 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
2182 {
2183 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
2184 ImGui::Separator();
2185
2186 //static int dummy_i = 0;
2187 //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0");
2188
2189 static bool dont_ask_me_next_time = false;
2190 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
2191 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
2192 ImGui::PopStyleVar();
2193
2194 if (ImGui::Button("OK", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
2195 ImGui::SetItemDefaultFocus();
2196 ImGui::SameLine();
2197 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
2198 ImGui::EndPopup();
2199 }
2200
2201 if (ImGui::Button("Stacked modals.."))
2202 ImGui::OpenPopup("Stacked 1");
2203 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
2204 {
2205 if (ImGui::BeginMenuBar())
2206 {
2207 if (ImGui::BeginMenu("File"))
2208 {
2209 if (ImGui::MenuItem("Dummy menu item")) {}
2210 ImGui::EndMenu();
2211 }
2212 ImGui::EndMenuBar();
2213 }
2214 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
2215
2216 // Testing behavior of widgets stacking their own regular popups over the modal.
2217 static int item = 1;
2218 static float color[4] = { 0.4f,0.7f,0.0f,0.5f };
2219 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
2220 ImGui::ColorEdit4("color", color);
2221
2222 if (ImGui::Button("Add another modal.."))
2223 ImGui::OpenPopup("Stacked 2");
2224
2225 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which will close the popup.
2226 // Note that the visibility state of popups is owned by imgui, so the input value of the bool actually doesn't matter here.
2227 bool dummy_open = true;
2228 if (ImGui::BeginPopupModal("Stacked 2", &dummy_open))
2229 {
2230 ImGui::Text("Hello from Stacked The Second!");
2231 if (ImGui::Button("Close"))
2232 ImGui::CloseCurrentPopup();
2233 ImGui::EndPopup();
2234 }
2235
2236 if (ImGui::Button("Close"))
2237 ImGui::CloseCurrentPopup();
2238 ImGui::EndPopup();
2239 }
2240
2241 ImGui::TreePop();
2242 }
2243
2244 if (ImGui::TreeNode("Menus inside a regular window"))
2245 {
2246 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
2247 ImGui::Separator();
2248 // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above.
2249 // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here
2250 // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus.
2251 ImGui::PushID("foo");
2252 ImGui::MenuItem("Menu item", "CTRL+M");
2253 if (ImGui::BeginMenu("Menu inside a regular window"))
2254 {
2255 ShowExampleMenuFile();
2256 ImGui::EndMenu();
2257 }
2258 ImGui::PopID();
2259 ImGui::Separator();
2260 ImGui::TreePop();
2261 }
2262 }
2263
2264 static void ShowDemoWindowColumns()
2265 {
2266 if (!ImGui::CollapsingHeader("Columns"))
2267 return;
2268
2269 ImGui::PushID("Columns");
2270
2271 // Basic columns
2272 if (ImGui::TreeNode("Basic"))
2273 {
2274 ImGui::Text("Without border:");
2275 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
2276 ImGui::Separator();
2277 for (int n = 0; n < 14; n++)
2278 {
2279 char label[32];
2280 sprintf(label, "Item %d", n);
2281 if (ImGui::Selectable(label)) {}
2282 //if (ImGui::Button(label, ImVec2(-1,0))) {}
2283 ImGui::NextColumn();
2284 }
2285 ImGui::Columns(1);
2286 ImGui::Separator();
2287
2288 ImGui::Text("With border:");
2289 ImGui::Columns(4, "mycolumns"); // 4-ways, with border
2290 ImGui::Separator();
2291 ImGui::Text("ID"); ImGui::NextColumn();
2292 ImGui::Text("Name"); ImGui::NextColumn();
2293 ImGui::Text("Path"); ImGui::NextColumn();
2294 ImGui::Text("Hovered"); ImGui::NextColumn();
2295 ImGui::Separator();
2296 const char* names[3] = { "One", "Two", "Three" };
2297 const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
2298 static int selected = -1;
2299 for (int i = 0; i < 3; i++)
2300 {
2301 char label[32];
2302 sprintf(label, "%04d", i);
2303 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
2304 selected = i;
2305 bool hovered = ImGui::IsItemHovered();
2306 ImGui::NextColumn();
2307 ImGui::Text(names[i]); ImGui::NextColumn();
2308 ImGui::Text(paths[i]); ImGui::NextColumn();
2309 ImGui::Text("%d", hovered); ImGui::NextColumn();
2310 }
2311 ImGui::Columns(1);
2312 ImGui::Separator();
2313 ImGui::TreePop();
2314 }
2315
2316 // Create multiple items in a same cell before switching to next column
2317 if (ImGui::TreeNode("Mixed items"))
2318 {
2319 ImGui::Columns(3, "mixed");
2320 ImGui::Separator();
2321
2322 ImGui::Text("Hello");
2323 ImGui::Button("Banana");
2324 ImGui::NextColumn();
2325
2326 ImGui::Text("ImGui");
2327 ImGui::Button("Apple");
2328 static float foo = 1.0f;
2329 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
2330 ImGui::Text("An extra line here.");
2331 ImGui::NextColumn();
2332
2333 ImGui::Text("Sailor");
2334 ImGui::Button("Corniflower");
2335 static float bar = 1.0f;
2336 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
2337 ImGui::NextColumn();
2338
2339 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
2340 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
2341 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
2342 ImGui::Columns(1);
2343 ImGui::Separator();
2344 ImGui::TreePop();
2345 }
2346
2347 // Word wrapping
2348 if (ImGui::TreeNode("Word-wrapping"))
2349 {
2350 ImGui::Columns(2, "word-wrapping");
2351 ImGui::Separator();
2352 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
2353 ImGui::TextWrapped("Hello Left");
2354 ImGui::NextColumn();
2355 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
2356 ImGui::TextWrapped("Hello Right");
2357 ImGui::Columns(1);
2358 ImGui::Separator();
2359 ImGui::TreePop();
2360 }
2361
2362 if (ImGui::TreeNode("Borders"))
2363 {
2364 // NB: Future columns API should allow automatic horizontal borders.
2365 static bool h_borders = true;
2366 static bool v_borders = true;
2367 ImGui::Checkbox("horizontal", &h_borders);
2368 ImGui::SameLine();
2369 ImGui::Checkbox("vertical", &v_borders);
2370 ImGui::Columns(4, NULL, v_borders);
2371 for (int i = 0; i < 4*3; i++)
2372 {
2373 if (h_borders && ImGui::GetColumnIndex() == 0)
2374 ImGui::Separator();
2375 ImGui::Text("%c%c%c", 'a'+i, 'a'+i, 'a'+i);
2376 ImGui::Text("Width %.2f\nOffset %.2f", ImGui::GetColumnWidth(), ImGui::GetColumnOffset());
2377 ImGui::NextColumn();
2378 }
2379 ImGui::Columns(1);
2380 if (h_borders)
2381 ImGui::Separator();
2382 ImGui::TreePop();
2383 }
2384
2385 // Scrolling columns
2386 /*
2387 if (ImGui::TreeNode("Vertical Scrolling"))
2388 {
2389 ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
2390 ImGui::Columns(3);
2391 ImGui::Text("ID"); ImGui::NextColumn();
2392 ImGui::Text("Name"); ImGui::NextColumn();
2393 ImGui::Text("Path"); ImGui::NextColumn();
2394 ImGui::Columns(1);
2395 ImGui::Separator();
2396 ImGui::EndChild();
2397 ImGui::BeginChild("##scrollingregion", ImVec2(0, 60));
2398 ImGui::Columns(3);
2399 for (int i = 0; i < 10; i++)
2400 {
2401 ImGui::Text("%04d", i); ImGui::NextColumn();
2402 ImGui::Text("Foobar"); ImGui::NextColumn();
2403 ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn();
2404 }
2405 ImGui::Columns(1);
2406 ImGui::EndChild();
2407 ImGui::TreePop();
2408 }
2409 */
2410
2411 if (ImGui::TreeNode("Horizontal Scrolling"))
2412 {
2413 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
2414 ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar);
2415 ImGui::Columns(10);
2416 int ITEMS_COUNT = 2000;
2417 ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list
2418 while (clipper.Step())
2419 {
2420 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
2421 for (int j = 0; j < 10; j++)
2422 {
2423 ImGui::Text("Line %d Column %d...", i, j);
2424 ImGui::NextColumn();
2425 }
2426 }
2427 ImGui::Columns(1);
2428 ImGui::EndChild();
2429 ImGui::TreePop();
2430 }
2431
2432 bool node_open = ImGui::TreeNode("Tree within single cell");
2433 ImGui::SameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell. There's no storage of state per-cell.");
2434 if (node_open)
2435 {
2436 ImGui::Columns(2, "tree items");
2437 ImGui::Separator();
2438 if (ImGui::TreeNode("Hello")) { ImGui::BulletText("Sailor"); ImGui::TreePop(); } ImGui::NextColumn();
2439 if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Marin"); ImGui::TreePop(); } ImGui::NextColumn();
2440 ImGui::Columns(1);
2441 ImGui::Separator();
2442 ImGui::TreePop();
2443 }
2444 ImGui::PopID();
2445 }
2446
2447 static void ShowDemoWindowMisc()
2448 {
2449 if (ImGui::CollapsingHeader("Filtering"))
2450 {
2451 static ImGuiTextFilter filter;
2452 ImGui::Text("Filter usage:\n"
2453 " \"\" display all lines\n"
2454 " \"xxx\" display lines containing \"xxx\"\n"
2455 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
2456 " \"-xxx\" hide lines containing \"xxx\"");
2457 filter.Draw();
2458 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
2459 for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
2460 if (filter.PassFilter(lines[i]))
2461 ImGui::BulletText("%s", lines[i]);
2462 }
2463
2464 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus"))
2465 {
2466 ImGuiIO& io = ImGui::GetIO();
2467
2468 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
2469 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
2470 ImGui::Text("WantTextInput: %d", io.WantTextInput);
2471 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos);
2472 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible);
2473
2474 if (ImGui::TreeNode("Keyboard, Mouse & Navigation State"))
2475 {
2476 if (ImGui::IsMousePosValid())
2477 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
2478 else
2479 ImGui::Text("Mouse pos: <INVALID>");
2480 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
2481 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]); }
2482 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); }
2483 ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
2484 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); }
2485 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
2486
2487 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 (%.02f secs)", i, io.KeysDownDuration[i]); }
2488 ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); }
2489 ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); }
2490 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
2491
2492 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]); }
2493 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); }
2494 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]); }
2495
2496 ImGui::Button("Hovering me sets the\nkeyboard capture flag");
2497 if (ImGui::IsItemHovered())
2498 ImGui::CaptureKeyboardFromApp(true);
2499 ImGui::SameLine();
2500 ImGui::Button("Holding me clears the\nthe keyboard capture flag");
2501 if (ImGui::IsItemActive())
2502 ImGui::CaptureKeyboardFromApp(false);
2503
2504 ImGui::TreePop();
2505 }
2506
2507 if (ImGui::TreeNode("Tabbing"))
2508 {
2509 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
2510 static char buf[32] = "dummy";
2511 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
2512 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
2513 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
2514 ImGui::PushAllowKeyboardFocus(false);
2515 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
2516 //ImGui::SameLine(); ShowHelperMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets.");
2517 ImGui::PopAllowKeyboardFocus();
2518 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
2519 ImGui::TreePop();
2520 }
2521
2522 if (ImGui::TreeNode("Focus from code"))
2523 {
2524 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
2525 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
2526 bool focus_3 = ImGui::Button("Focus on 3");
2527 int has_focus = 0;
2528 static char buf[128] = "click on a button to set focus";
2529
2530 if (focus_1) ImGui::SetKeyboardFocusHere();
2531 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
2532 if (ImGui::IsItemActive()) has_focus = 1;
2533
2534 if (focus_2) ImGui::SetKeyboardFocusHere();
2535 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
2536 if (ImGui::IsItemActive()) has_focus = 2;
2537
2538 ImGui::PushAllowKeyboardFocus(false);
2539 if (focus_3) ImGui::SetKeyboardFocusHere();
2540 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
2541 if (ImGui::IsItemActive()) has_focus = 3;
2542 ImGui::PopAllowKeyboardFocus();
2543
2544 if (has_focus)
2545 ImGui::Text("Item with focus: %d", has_focus);
2546 else
2547 ImGui::Text("Item with focus: <none>");
2548
2549 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
2550 static float f3[3] = { 0.0f, 0.0f, 0.0f };
2551 int focus_ahead = -1;
2552 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
2553 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
2554 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
2555 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
2556 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
2557
2558 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
2559 ImGui::TreePop();
2560 }
2561
2562 if (ImGui::TreeNode("Dragging"))
2563 {
2564 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
2565 for (int button = 0; button < 3; button++)
2566 ImGui::Text("IsMouseDragging(%d):\n w/ default threshold: %d,\n w/ zero threshold: %d\n w/ large threshold: %d",
2567 button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f));
2568 ImGui::Button("Drag Me");
2569 if (ImGui::IsItemActive())
2570 {
2571 // Draw a line between the button and the mouse cursor
2572 ImDrawList* draw_list = ImGui::GetWindowDrawList();
2573 draw_list->PushClipRectFullScreen();
2574 draw_list->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f);
2575 draw_list->PopClipRect();
2576
2577 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold)
2578 // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta()
2579 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
2580 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
2581 ImVec2 mouse_delta = io.MouseDelta;
2582 ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y);
2583 }
2584 ImGui::TreePop();
2585 }
2586
2587 if (ImGui::TreeNode("Mouse cursors"))
2588 {
2589 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand" };
2590 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
2591
2592 ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]);
2593 ImGui::Text("Hover to see mouse cursors:");
2594 ImGui::SameLine(); ShowHelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it.");
2595 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
2596 {
2597 char label[32];
2598 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
2599 ImGui::Bullet(); ImGui::Selectable(label, false);
2600 if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
2601 ImGui::SetMouseCursor(i);
2602 }
2603 ImGui::TreePop();
2604 }
2605 }
2606 }
2607
2608 //-----------------------------------------------------------------------------
2609 // [SECTION] About Window / ShowAboutWindow()
2610 // Access from ImGui Demo -> Help -> About
2611 //-----------------------------------------------------------------------------
2612
2613 void ImGui::ShowAboutWindow(bool* p_open)
2614 {
2615 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
2616 {
2617 ImGui::End();
2618 return;
2619 }
2620 ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
2621 ImGui::Separator();
2622 ImGui::Text("By Omar Cornut and all dear imgui contributors.");
2623 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
2624
2625 static bool show_config_info = false;
2626 ImGui::Checkbox("Config/Build Information", &show_config_info);
2627 if (show_config_info)
2628 {
2629 ImGuiIO& io = ImGui::GetIO();
2630 ImGuiStyle& style = ImGui::GetStyle();
2631
2632 bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
2633 ImGui::BeginChildFrame(ImGui::GetID("cfginfos"), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18), ImGuiWindowFlags_NoMove);
2634 if (copy_to_clipboard)
2635 ImGui::LogToClipboard();
2636
2637 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
2638 ImGui::Separator();
2639 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
2640 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
2641 #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
2642 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
2643 #endif
2644 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
2645 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
2646 #endif
2647 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
2648 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
2649 #endif
2650 #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
2651 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
2652 #endif
2653 #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
2654 ImGui::Text("define: IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS");
2655 #endif
2656 #ifdef IMGUI_DISABLE_MATH_FUNCTIONS
2657 ImGui::Text("define: IMGUI_DISABLE_MATH_FUNCTIONS");
2658 #endif
2659 #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
2660 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
2661 #endif
2662 #ifdef IMGUI_USE_BGRA_PACKED_COLOR
2663 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
2664 #endif
2665 #ifdef _WIN32
2666 ImGui::Text("define: _WIN32");
2667 #endif
2668 #ifdef _WIN64
2669 ImGui::Text("define: _WIN64");
2670 #endif
2671 #ifdef __linux__
2672 ImGui::Text("define: __linux__");
2673 #endif
2674 #ifdef __APPLE__
2675 ImGui::Text("define: __APPLE__");
2676 #endif
2677 #ifdef _MSC_VER
2678 ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
2679 #endif
2680 #ifdef __MINGW32__
2681 ImGui::Text("define: __MINGW32__");
2682 #endif
2683 #ifdef __MINGW64__
2684 ImGui::Text("define: __MINGW64__");
2685 #endif
2686 #ifdef __GNUC__
2687 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
2688 #endif
2689 #ifdef __clang_version__
2690 ImGui::Text("define: __clang_version__=%s", __clang_version__);
2691 #endif
2692 ImGui::Separator();
2693 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
2694 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
2695 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
2696 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard");
2697 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad");
2698 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos");
2699 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard");
2700 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse");
2701 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange");
2702 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor");
2703 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors");
2704 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
2705 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
2706 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
2707 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
2708 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
2709 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
2710 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
2711 ImGui::Separator();
2712 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);
2713 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
2714 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
2715 ImGui::Separator();
2716 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
2717 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
2718 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
2719 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
2720 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
2721 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
2722 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
2723
2724 if (copy_to_clipboard)
2725 ImGui::LogFinish();
2726 ImGui::EndChildFrame();
2727 }
2728 ImGui::End();
2729 }
2730
2731 //-----------------------------------------------------------------------------
2732 // [SECTION] Style Editor / ShowStyleEditor()
2733 //-----------------------------------------------------------------------------
2734
2735 // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
2736 // Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally.
2737 bool ImGui::ShowStyleSelector(const char* label)
2738 {
2739 static int style_idx = -1;
2740 if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))
2741 {
2742 switch (style_idx)
2743 {
2744 case 0: ImGui::StyleColorsClassic(); break;
2745 case 1: ImGui::StyleColorsDark(); break;
2746 case 2: ImGui::StyleColorsLight(); break;
2747 }
2748 return true;
2749 }
2750 return false;
2751 }
2752
2753 // Demo helper function to select among loaded fonts.
2754 // Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one.
2755 void ImGui::ShowFontSelector(const char* label)
2756 {
2757 ImGuiIO& io = ImGui::GetIO();
2758 ImFont* font_current = ImGui::GetFont();
2759 if (ImGui::BeginCombo(label, font_current->GetDebugName()))
2760 {
2761 for (int n = 0; n < io.Fonts->Fonts.Size; n++)
2762 {
2763 ImFont* font = io.Fonts->Fonts[n];
2764 ImGui::PushID((void*)font);
2765 if (ImGui::Selectable(font->GetDebugName(), font == font_current))
2766 io.FontDefault = font;
2767 ImGui::PopID();
2768 }
2769 ImGui::EndCombo();
2770 }
2771 ImGui::SameLine();
2772 ShowHelpMarker(
2773 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
2774 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
2775 "- Read FAQ and documentation in misc/fonts/ for more details.\n"
2776 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
2777 }
2778
2779 void ImGui::ShowStyleEditor(ImGuiStyle* ref)
2780 {
2781 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference)
2782 ImGuiStyle& style = ImGui::GetStyle();
2783 static ImGuiStyle ref_saved_style;
2784
2785 // Default to using internal storage as reference
2786 static bool init = true;
2787 if (init && ref == NULL)
2788 ref_saved_style = style;
2789 init = false;
2790 if (ref == NULL)
2791 ref = &ref_saved_style;
2792
2793 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
2794
2795 if (ImGui::ShowStyleSelector("Colors##Selector"))
2796 ref_saved_style = style;
2797 ImGui::ShowFontSelector("Fonts##Selector");
2798
2799 // Simplified Settings
2800 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
2801 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
2802 { bool window_border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; }
2803 ImGui::SameLine();
2804 { bool frame_border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; }
2805 ImGui::SameLine();
2806 { bool popup_border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; }
2807
2808 // Save/Revert button
2809 if (ImGui::Button("Save Ref"))
2810 *ref = ref_saved_style = style;
2811 ImGui::SameLine();
2812 if (ImGui::Button("Revert Ref"))
2813 style = *ref;
2814 ImGui::SameLine();
2815 ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere.");
2816
2817 ImGui::Separator();
2818
2819 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
2820 {
2821 if (ImGui::BeginTabItem("Sizes"))
2822 {
2823 ImGui::Text("Main");
2824 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
2825 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
2826 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
2827 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
2828 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
2829 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
2830 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
2831 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
2832 ImGui::Text("Borders");
2833 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
2834 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
2835 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
2836 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
2837 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
2838 ImGui::Text("Rounding");
2839 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
2840 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
2841 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
2842 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
2843 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
2844 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
2845 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
2846 ImGui::Text("Alignment");
2847 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
2848 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content.");
2849 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a selectable is larger than its text content.");
2850 ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
2851 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
2852 ImGui::EndTabItem();
2853 }
2854
2855 if (ImGui::BeginTabItem("Colors"))
2856 {
2857 static int output_dest = 0;
2858 static bool output_only_modified = true;
2859 if (ImGui::Button("Export Unsaved"))
2860 {
2861 if (output_dest == 0)
2862 ImGui::LogToClipboard();
2863 else
2864 ImGui::LogToTTY();
2865 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
2866 for (int i = 0; i < ImGuiCol_COUNT; i++)
2867 {
2868 const ImVec4& col = style.Colors[i];
2869 const char* name = ImGui::GetStyleColorName(i);
2870 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
2871 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
2872 }
2873 ImGui::LogFinish();
2874 }
2875 ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth();
2876 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
2877
2878 static ImGuiTextFilter filter;
2879 filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
2880
2881 static ImGuiColorEditFlags alpha_flags = 0;
2882 ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine();
2883 ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine();
2884 ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::SameLine();
2885 ShowHelpMarker("In the color list:\nLeft-click on colored square to open color picker,\nRight-click to open edit options menu.");
2886
2887 ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
2888 ImGui::PushItemWidth(-160);
2889 for (int i = 0; i < ImGuiCol_COUNT; i++)
2890 {
2891 const char* name = ImGui::GetStyleColorName(i);
2892 if (!filter.PassFilter(name))
2893 continue;
2894 ImGui::PushID(i);
2895 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
2896 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
2897 {
2898 // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons.
2899 // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient!
2900 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i];
2901 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i];
2902 }
2903 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
2904 ImGui::TextUnformatted(name);
2905 ImGui::PopID();
2906 }
2907 ImGui::PopItemWidth();
2908 ImGui::EndChild();
2909
2910 ImGui::EndTabItem();
2911 }
2912
2913 if (ImGui::BeginTabItem("Fonts"))
2914 {
2915 ImGuiIO& io = ImGui::GetIO();
2916 ImFontAtlas* atlas = io.Fonts;
2917 ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading.");
2918 ImGui::PushItemWidth(120);
2919 for (int i = 0; i < atlas->Fonts.Size; i++)
2920 {
2921 ImFont* font = atlas->Fonts[i];
2922 ImGui::PushID(font);
2923 bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
2924 ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; }
2925 if (font_details_opened)
2926 {
2927 ImGui::PushFont(font);
2928 ImGui::Text("The quick brown fox jumps over the lazy dog");
2929 ImGui::PopFont();
2930 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font
2931 ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)");
2932 ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f");
2933 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
2934 ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar);
2935 const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface);
2936 ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt);
2937 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
2938 if (const ImFontConfig* cfg = &font->ConfigData[config_i])
2939 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
2940 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
2941 {
2942 // Display all glyphs of the fonts in separate pages of 256 characters
2943 for (int base = 0; base < 0x10000; base += 256)
2944 {
2945 int count = 0;
2946 for (int n = 0; n < 256; n++)
2947 count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;
2948 if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
2949 {
2950 float cell_size = font->FontSize * 1;
2951 float cell_spacing = style.ItemSpacing.y;
2952 ImVec2 base_pos = ImGui::GetCursorScreenPos();
2953 ImDrawList* draw_list = ImGui::GetWindowDrawList();
2954 for (int n = 0; n < 256; n++)
2955 {
2956 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
2957 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
2958 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
2959 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
2960 if (glyph)
2961 font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string.
2962 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
2963 {
2964 ImGui::BeginTooltip();
2965 ImGui::Text("Codepoint: U+%04X", base + n);
2966 ImGui::Separator();
2967 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
2968 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
2969 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
2970 ImGui::EndTooltip();
2971 }
2972 }
2973 ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
2974 ImGui::TreePop();
2975 }
2976 }
2977 ImGui::TreePop();
2978 }
2979 ImGui::TreePop();
2980 }
2981 ImGui::PopID();
2982 }
2983 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
2984 {
2985 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
2986 ImGui::TreePop();
2987 }
2988
2989 static float window_scale = 1.0f;
2990 if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window
2991 ImGui::SetWindowFontScale(window_scale);
2992 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything
2993 ImGui::PopItemWidth();
2994
2995 ImGui::EndTabItem();
2996 }
2997
2998 if (ImGui::BeginTabItem("Rendering"))
2999 {
3000 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
3001 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
3002 ImGui::PushItemWidth(100);
3003 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f);
3004 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
3005 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.
3006 ImGui::PopItemWidth();
3007
3008 ImGui::EndTabItem();
3009 }
3010
3011 ImGui::EndTabBar();
3012 }
3013
3014 ImGui::PopItemWidth();
3015 }
3016
3017 //-----------------------------------------------------------------------------
3018 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
3019 //-----------------------------------------------------------------------------
3020
3021 // Demonstrate creating a fullscreen menu bar and populating it.
3022 static void ShowExampleAppMainMenuBar()
3023 {
3024 if (ImGui::BeginMainMenuBar())
3025 {
3026 if (ImGui::BeginMenu("File"))
3027 {
3028 ShowExampleMenuFile();
3029 ImGui::EndMenu();
3030 }
3031 if (ImGui::BeginMenu("Edit"))
3032 {
3033 if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
3034 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
3035 ImGui::Separator();
3036 if (ImGui::MenuItem("Cut", "CTRL+X")) {}
3037 if (ImGui::MenuItem("Copy", "CTRL+C")) {}
3038 if (ImGui::MenuItem("Paste", "CTRL+V")) {}
3039 ImGui::EndMenu();
3040 }
3041 ImGui::EndMainMenuBar();
3042 }
3043 }
3044
3045 static void ShowExampleMenuFile()
3046 {
3047 ImGui::MenuItem("(dummy menu)", NULL, false, false);
3048 if (ImGui::MenuItem("New")) {}
3049 if (ImGui::MenuItem("Open", "Ctrl+O")) {}
3050 if (ImGui::BeginMenu("Open Recent"))
3051 {
3052 ImGui::MenuItem("fish_hat.c");
3053 ImGui::MenuItem("fish_hat.inl");
3054 ImGui::MenuItem("fish_hat.h");
3055 if (ImGui::BeginMenu("More.."))
3056 {
3057 ImGui::MenuItem("Hello");
3058 ImGui::MenuItem("Sailor");
3059 if (ImGui::BeginMenu("Recurse.."))
3060 {
3061 ShowExampleMenuFile();
3062 ImGui::EndMenu();
3063 }
3064 ImGui::EndMenu();
3065 }
3066 ImGui::EndMenu();
3067 }
3068 if (ImGui::MenuItem("Save", "Ctrl+S")) {}
3069 if (ImGui::MenuItem("Save As..")) {}
3070 ImGui::Separator();
3071 if (ImGui::BeginMenu("Options"))
3072 {
3073 static bool enabled = true;
3074 ImGui::MenuItem("Enabled", "", &enabled);
3075 ImGui::BeginChild("child", ImVec2(0, 60), true);
3076 for (int i = 0; i < 10; i++)
3077 ImGui::Text("Scrolling Text %d", i);
3078 ImGui::EndChild();
3079 static float f = 0.5f;
3080 static int n = 0;
3081 static bool b = true;
3082 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
3083 ImGui::InputFloat("Input", &f, 0.1f);
3084 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
3085 ImGui::Checkbox("Check", &b);
3086 ImGui::EndMenu();
3087 }
3088 if (ImGui::BeginMenu("Colors"))
3089 {
3090 float sz = ImGui::GetTextLineHeight();
3091 for (int i = 0; i < ImGuiCol_COUNT; i++)
3092 {
3093 const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
3094 ImVec2 p = ImGui::GetCursorScreenPos();
3095 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x+sz, p.y+sz), ImGui::GetColorU32((ImGuiCol)i));
3096 ImGui::Dummy(ImVec2(sz, sz));
3097 ImGui::SameLine();
3098 ImGui::MenuItem(name);
3099 }
3100 ImGui::EndMenu();
3101 }
3102 if (ImGui::BeginMenu("Disabled", false)) // Disabled
3103 {
3104 IM_ASSERT(0);
3105 }
3106 if (ImGui::MenuItem("Checked", NULL, true)) {}
3107 if (ImGui::MenuItem("Quit", "Alt+F4")) {}
3108 }
3109
3110 //-----------------------------------------------------------------------------
3111 // [SECTION] Example App: Debug Console / ShowExampleAppConsole()
3112 //-----------------------------------------------------------------------------
3113
3114 // Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
3115 // For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions.
3116 struct ExampleAppConsole
3117 {
3118 char InputBuf[256];
3119 ImVector<char*> Items;
3120 ImVector<const char*> Commands;
3121 ImVector<char*> History;
3122 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
3123 ImGuiTextFilter Filter;
3124 bool AutoScroll;
3125 bool ScrollToBottom;
3126
3127 ExampleAppConsole()
3128 {
3129 ClearLog();
3130 memset(InputBuf, 0, sizeof(InputBuf));
3131 HistoryPos = -1;
3132 Commands.push_back("HELP");
3133 Commands.push_back("HISTORY");
3134 Commands.push_back("CLEAR");
3135 Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches.
3136 AutoScroll = true;
3137 ScrollToBottom = true;
3138 AddLog("Welcome to Dear ImGui!");
3139 }
3140 ~ExampleAppConsole()
3141 {
3142 ClearLog();
3143 for (int i = 0; i < History.Size; i++)
3144 free(History[i]);
3145 }
3146
3147 // Portable helpers
3148 static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; }
3149 static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; }
3150 static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)str, len); }
3151 static void Strtrim(char* str) { char* str_end = str + strlen(str); while (str_end > str && str_end[-1] == ' ') str_end--; *str_end = 0; }
3152
3153 void ClearLog()
3154 {
3155 for (int i = 0; i < Items.Size; i++)
3156 free(Items[i]);
3157 Items.clear();
3158 ScrollToBottom = true;
3159 }
3160
3161 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
3162 {
3163 // FIXME-OPT
3164 char buf[1024];
3165 va_list args;
3166 va_start(args, fmt);
3167 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
3168 buf[IM_ARRAYSIZE(buf)-1] = 0;
3169 va_end(args);
3170 Items.push_back(Strdup(buf));
3171 if (AutoScroll)
3172 ScrollToBottom = true;
3173 }
3174
3175 void Draw(const char* title, bool* p_open)
3176 {
3177 ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver);
3178 if (!ImGui::Begin(title, p_open))
3179 {
3180 ImGui::End();
3181 return;
3182 }
3183
3184 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar.
3185 // Here we create a context menu only available from the title bar.
3186 if (ImGui::BeginPopupContextItem())
3187 {
3188 if (ImGui::MenuItem("Close Console"))
3189 *p_open = false;
3190 ImGui::EndPopup();
3191 }
3192
3193 ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
3194 ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion.");
3195
3196 // TODO: display items starting from the bottom
3197
3198 if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine();
3199 if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine();
3200 if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine();
3201 bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine();
3202 if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true;
3203 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
3204
3205 ImGui::Separator();
3206
3207 // Options menu
3208 if (ImGui::BeginPopup("Options"))
3209 {
3210 if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
3211 if (AutoScroll)
3212 ScrollToBottom = true;
3213 ImGui::EndPopup();
3214 }
3215
3216 // Options, Filter
3217 if (ImGui::Button("Options"))
3218 ImGui::OpenPopup("Options");
3219 ImGui::SameLine();
3220 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
3221 ImGui::Separator();
3222
3223 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text
3224 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText
3225 if (ImGui::BeginPopupContextWindow())
3226 {
3227 if (ImGui::Selectable("Clear")) ClearLog();
3228 ImGui::EndPopup();
3229 }
3230
3231 // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
3232 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items.
3233 // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements.
3234 // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with:
3235 // ImGuiListClipper clipper(Items.Size);
3236 // while (clipper.Step())
3237 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
3238 // However, note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list.
3239 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter,
3240 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code!
3241 // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list.
3242 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing
3243 if (copy_to_clipboard)
3244 ImGui::LogToClipboard();
3245 for (int i = 0; i < Items.Size; i++)
3246 {
3247 const char* item = Items[i];
3248 if (!Filter.PassFilter(item))
3249 continue;
3250
3251 // Normally you would store more information in your item (e.g. make Items[] an array of structure, store color/type etc.)
3252 bool pop_color = false;
3253 if (strstr(item, "[error]")) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f)); pop_color = true; }
3254 else if (strncmp(item, "# ", 2) == 0) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f)); pop_color = true; }
3255 ImGui::TextUnformatted(item);
3256 if (pop_color)
3257 ImGui::PopStyleColor();
3258 }
3259 if (copy_to_clipboard)
3260 ImGui::LogFinish();
3261 if (ScrollToBottom)
3262 ImGui::SetScrollHereY(1.0f);
3263 ScrollToBottom = false;
3264 ImGui::PopStyleVar();
3265 ImGui::EndChild();
3266 ImGui::Separator();
3267
3268 // Command-line
3269 bool reclaim_focus = false;
3270 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this))
3271 {
3272 char* s = InputBuf;
3273 Strtrim(s);
3274 if (s[0])
3275 ExecCommand(s);
3276 strcpy(s, "");
3277 reclaim_focus = true;
3278 }
3279
3280 // Auto-focus on window apparition
3281 ImGui::SetItemDefaultFocus();
3282 if (reclaim_focus)
3283 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
3284
3285 ImGui::End();
3286 }
3287
3288 void ExecCommand(const char* command_line)
3289 {
3290 AddLog("# %s\n", command_line);
3291
3292 // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal.
3293 HistoryPos = -1;
3294 for (int i = History.Size-1; i >= 0; i--)
3295 if (Stricmp(History[i], command_line) == 0)
3296 {
3297 free(History[i]);
3298 History.erase(History.begin() + i);
3299 break;
3300 }
3301 History.push_back(Strdup(command_line));
3302
3303 // Process command
3304 if (Stricmp(command_line, "CLEAR") == 0)
3305 {
3306 ClearLog();
3307 }
3308 else if (Stricmp(command_line, "HELP") == 0)
3309 {
3310 AddLog("Commands:");
3311 for (int i = 0; i < Commands.Size; i++)
3312 AddLog("- %s", Commands[i]);
3313 }
3314 else if (Stricmp(command_line, "HISTORY") == 0)
3315 {
3316 int first = History.Size - 10;
3317 for (int i = first > 0 ? first : 0; i < History.Size; i++)
3318 AddLog("%3d: %s\n", i, History[i]);
3319 }
3320 else
3321 {
3322 AddLog("Unknown command: '%s'\n", command_line);
3323 }
3324
3325 // On commad input, we scroll to bottom even if AutoScroll==false
3326 ScrollToBottom = true;
3327 }
3328
3329 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks
3330 {
3331 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
3332 return console->TextEditCallback(data);
3333 }
3334
3335 int TextEditCallback(ImGuiInputTextCallbackData* data)
3336 {
3337 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
3338 switch (data->EventFlag)
3339 {
3340 case ImGuiInputTextFlags_CallbackCompletion:
3341 {
3342 // Example of TEXT COMPLETION
3343
3344 // Locate beginning of current word
3345 const char* word_end = data->Buf + data->CursorPos;
3346 const char* word_start = word_end;
3347 while (word_start > data->Buf)
3348 {
3349 const char c = word_start[-1];
3350 if (c == ' ' || c == '\t' || c == ',' || c == ';')
3351 break;
3352 word_start--;
3353 }
3354
3355 // Build a list of candidates
3356 ImVector<const char*> candidates;
3357 for (int i = 0; i < Commands.Size; i++)
3358 if (Strnicmp(Commands[i], word_start, (int)(word_end-word_start)) == 0)
3359 candidates.push_back(Commands[i]);
3360
3361 if (candidates.Size == 0)
3362 {
3363 // No match
3364 AddLog("No match for \"%.*s\"!\n", (int)(word_end-word_start), word_start);
3365 }
3366 else if (candidates.Size == 1)
3367 {
3368 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing
3369 data->DeleteChars((int)(word_start-data->Buf), (int)(word_end-word_start));
3370 data->InsertChars(data->CursorPos, candidates[0]);
3371 data->InsertChars(data->CursorPos, " ");
3372 }
3373 else
3374 {
3375 // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY"
3376 int match_len = (int)(word_end - word_start);
3377 for (;;)
3378 {
3379 int c = 0;
3380 bool all_candidates_matches = true;
3381 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
3382 if (i == 0)
3383 c = toupper(candidates[i][match_len]);
3384 else if (c == 0 || c != toupper(candidates[i][match_len]))
3385 all_candidates_matches = false;
3386 if (!all_candidates_matches)
3387 break;
3388 match_len++;
3389 }
3390
3391 if (match_len > 0)
3392 {
3393 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end-word_start));
3394 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
3395 }
3396
3397 // List matches
3398 AddLog("Possible matches:\n");
3399 for (int i = 0; i < candidates.Size; i++)
3400 AddLog("- %s\n", candidates[i]);
3401 }
3402
3403 break;
3404 }
3405 case ImGuiInputTextFlags_CallbackHistory:
3406 {
3407 // Example of HISTORY
3408 const int prev_history_pos = HistoryPos;
3409 if (data->EventKey == ImGuiKey_UpArrow)
3410 {
3411 if (HistoryPos == -1)
3412 HistoryPos = History.Size - 1;
3413 else if (HistoryPos > 0)
3414 HistoryPos--;
3415 }
3416 else if (data->EventKey == ImGuiKey_DownArrow)
3417 {
3418 if (HistoryPos != -1)
3419 if (++HistoryPos >= History.Size)
3420 HistoryPos = -1;
3421 }
3422
3423 // A better implementation would preserve the data on the current input line along with cursor position.
3424 if (prev_history_pos != HistoryPos)
3425 {
3426 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
3427 data->DeleteChars(0, data->BufTextLen);
3428 data->InsertChars(0, history_str);
3429 }
3430 }
3431 }
3432 return 0;
3433 }
3434 };
3435
3436 static void ShowExampleAppConsole(bool* p_open)
3437 {
3438 static ExampleAppConsole console;
3439 console.Draw("Example: Console", p_open);
3440 }
3441
3442 //-----------------------------------------------------------------------------
3443 // [SECTION] Example App: Debug Log / ShowExampleAppLog()
3444 //-----------------------------------------------------------------------------
3445
3446 // Usage:
3447 // static ExampleAppLog my_log;
3448 // my_log.AddLog("Hello %d world\n", 123);
3449 // my_log.Draw("title");
3450 struct ExampleAppLog
3451 {
3452 ImGuiTextBuffer Buf;
3453 ImGuiTextFilter Filter;
3454 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines
3455 bool AutoScroll;
3456 bool ScrollToBottom;
3457
3458 ExampleAppLog()
3459 {
3460 AutoScroll = true;
3461 ScrollToBottom = false;
3462 Clear();
3463 }
3464
3465 void Clear()
3466 {
3467 Buf.clear();
3468 LineOffsets.clear();
3469 LineOffsets.push_back(0);
3470 }
3471
3472 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
3473 {
3474 int old_size = Buf.size();
3475 va_list args;
3476 va_start(args, fmt);
3477 Buf.appendfv(fmt, args);
3478 va_end(args);
3479 for (int new_size = Buf.size(); old_size < new_size; old_size++)
3480 if (Buf[old_size] == '\n')
3481 LineOffsets.push_back(old_size + 1);
3482 if (AutoScroll)
3483 ScrollToBottom = true;
3484 }
3485
3486 void Draw(const char* title, bool* p_open = NULL)
3487 {
3488 if (!ImGui::Begin(title, p_open))
3489 {
3490 ImGui::End();
3491 return;
3492 }
3493
3494 // Options menu
3495 if (ImGui::BeginPopup("Options"))
3496 {
3497 if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
3498 if (AutoScroll)
3499 ScrollToBottom = true;
3500 ImGui::EndPopup();
3501 }
3502
3503 // Main window
3504 if (ImGui::Button("Options"))
3505 ImGui::OpenPopup("Options");
3506 ImGui::SameLine();
3507 bool clear = ImGui::Button("Clear");
3508 ImGui::SameLine();
3509 bool copy = ImGui::Button("Copy");
3510 ImGui::SameLine();
3511 Filter.Draw("Filter", -100.0f);
3512
3513 ImGui::Separator();
3514 ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar);
3515
3516 if (clear)
3517 Clear();
3518 if (copy)
3519 ImGui::LogToClipboard();
3520
3521 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
3522 const char* buf = Buf.begin();
3523 const char* buf_end = Buf.end();
3524 if (Filter.IsActive())
3525 {
3526 // In this example we don't use the clipper when Filter is enabled.
3527 // This is because we don't have a random access on the result on our filter.
3528 // A real application processing logs with ten of thousands of entries may want to store the result of search/filter.
3529 // especially if the filtering function is not trivial (e.g. reg-exp).
3530 for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
3531 {
3532 const char* line_start = buf + LineOffsets[line_no];
3533 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
3534 if (Filter.PassFilter(line_start, line_end))
3535 ImGui::TextUnformatted(line_start, line_end);
3536 }
3537 }
3538 else
3539 {
3540 // The simplest and easy way to display the entire buffer:
3541 // ImGui::TextUnformatted(buf_begin, buf_end);
3542 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward to skip non-visible lines.
3543 // Here we instead demonstrate using the clipper to only process lines that are within the visible area.
3544 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them on your side is recommended.
3545 // Using ImGuiListClipper requires A) random access into your data, and B) items all being the same height,
3546 // both of which we can handle since we an array pointing to the beginning of each line of text.
3547 // When using the filter (in the block of code above) we don't have random access into the data to display anymore, which is why we don't use the clipper.
3548 // Storing or skimming through the search result would make it possible (and would be recommended if you want to search through tens of thousands of entries)
3549 ImGuiListClipper clipper;
3550 clipper.Begin(LineOffsets.Size);
3551 while (clipper.Step())
3552 {
3553 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
3554 {
3555 const char* line_start = buf + LineOffsets[line_no];
3556 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
3557 ImGui::TextUnformatted(line_start, line_end);
3558 }
3559 }
3560 clipper.End();
3561 }
3562 ImGui::PopStyleVar();
3563
3564 if (ScrollToBottom)
3565 ImGui::SetScrollHereY(1.0f);
3566 ScrollToBottom = false;
3567 ImGui::EndChild();
3568 ImGui::End();
3569 }
3570 };
3571
3572 // Demonstrate creating a simple log window with basic filtering.
3573 static void ShowExampleAppLog(bool* p_open)
3574 {
3575 static ExampleAppLog log;
3576
3577 // For the demo: add a debug button _BEFORE_ the normal log window contents
3578 // We take advantage of the fact that multiple calls to Begin()/End() are appending to the same window.
3579 // Most of the contents of the window will be added by the log.Draw() call.
3580 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
3581 ImGui::Begin("Example: Log", p_open);
3582 if (ImGui::SmallButton("[Debug] Add 5 entries"))
3583 {
3584 static int counter = 0;
3585 for (int n = 0; n < 5; n++)
3586 {
3587 const char* categories[3] = { "info", "warn", "error" };
3588 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
3589 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
3590 ImGui::GetFrameCount(), categories[counter % IM_ARRAYSIZE(categories)], ImGui::GetTime(), words[counter % IM_ARRAYSIZE(words)]);
3591 counter++;
3592 }
3593 }
3594 ImGui::End();
3595
3596 log.Draw("Example: Log", p_open);
3597 }
3598
3599 //-----------------------------------------------------------------------------
3600 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
3601 //-----------------------------------------------------------------------------
3602
3603 // Demonstrate create a window with multiple child windows.
3604 static void ShowExampleAppLayout(bool* p_open)
3605 {
3606 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
3607 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
3608 {
3609 if (ImGui::BeginMenuBar())
3610 {
3611 if (ImGui::BeginMenu("File"))
3612 {
3613 if (ImGui::MenuItem("Close")) *p_open = false;
3614 ImGui::EndMenu();
3615 }
3616 ImGui::EndMenuBar();
3617 }
3618
3619 // left
3620 static int selected = 0;
3621 ImGui::BeginChild("left pane", ImVec2(150, 0), true);
3622 for (int i = 0; i < 100; i++)
3623 {
3624 char label[128];
3625 sprintf(label, "MyObject %d", i);
3626 if (ImGui::Selectable(label, selected == i))
3627 selected = i;
3628 }
3629 ImGui::EndChild();
3630 ImGui::SameLine();
3631
3632 // right
3633 ImGui::BeginGroup();
3634 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
3635 ImGui::Text("MyObject: %d", selected);
3636 ImGui::Separator();
3637 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
3638 {
3639 if (ImGui::BeginTabItem("Description"))
3640 {
3641 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
3642 ImGui::EndTabItem();
3643 }
3644 if (ImGui::BeginTabItem("Details"))
3645 {
3646 ImGui::Text("ID: 0123456789");
3647 ImGui::EndTabItem();
3648 }
3649 ImGui::EndTabBar();
3650 }
3651 ImGui::EndChild();
3652 if (ImGui::Button("Revert")) {}
3653 ImGui::SameLine();
3654 if (ImGui::Button("Save")) {}
3655 ImGui::EndGroup();
3656 }
3657 ImGui::End();
3658 }
3659
3660 //-----------------------------------------------------------------------------
3661 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
3662 //-----------------------------------------------------------------------------
3663
3664 // Demonstrate create a simple property editor.
3665 static void ShowExampleAppPropertyEditor(bool* p_open)
3666 {
3667 ImGui::SetNextWindowSize(ImVec2(430,450), ImGuiCond_FirstUseEver);
3668 if (!ImGui::Begin("Example: Property editor", p_open))
3669 {
3670 ImGui::End();
3671 return;
3672 }
3673
3674 ShowHelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API.");
3675
3676 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2,2));
3677 ImGui::Columns(2);
3678 ImGui::Separator();
3679
3680 struct funcs
3681 {
3682 static void ShowDummyObject(const char* prefix, int uid)
3683 {
3684 ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
3685 ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high.
3686 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
3687 ImGui::NextColumn();
3688 ImGui::AlignTextToFramePadding();
3689 ImGui::Text("my sailor is rich");
3690 ImGui::NextColumn();
3691 if (node_open)
3692 {
3693 static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f };
3694 for (int i = 0; i < 8; i++)
3695 {
3696 ImGui::PushID(i); // Use field index as identifier.
3697 if (i < 2)
3698 {
3699 ShowDummyObject("Child", 424242);
3700 }
3701 else
3702 {
3703 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well)
3704 ImGui::AlignTextToFramePadding();
3705 ImGui::TreeNodeEx("Field", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet, "Field_%d", i);
3706 ImGui::NextColumn();
3707 ImGui::PushItemWidth(-1);
3708 if (i >= 5)
3709 ImGui::InputFloat("##value", &dummy_members[i], 1.0f);
3710 else
3711 ImGui::DragFloat("##value", &dummy_members[i], 0.01f);
3712 ImGui::PopItemWidth();
3713 ImGui::NextColumn();
3714 }
3715 ImGui::PopID();
3716 }
3717 ImGui::TreePop();
3718 }
3719 ImGui::PopID();
3720 }
3721 };
3722
3723 // Iterate dummy objects with dummy members (all the same data)
3724 for (int obj_i = 0; obj_i < 3; obj_i++)
3725 funcs::ShowDummyObject("Object", obj_i);
3726
3727 ImGui::Columns(1);
3728 ImGui::Separator();
3729 ImGui::PopStyleVar();
3730 ImGui::End();
3731 }
3732
3733 //-----------------------------------------------------------------------------
3734 // [SECTION] Example App: Long Text / ShowExampleAppLongText()
3735 //-----------------------------------------------------------------------------
3736
3737 // Demonstrate/test rendering huge amount of text, and the incidence of clipping.
3738 static void ShowExampleAppLongText(bool* p_open)
3739 {
3740 ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver);
3741 if (!ImGui::Begin("Example: Long text display", p_open))
3742 {
3743 ImGui::End();
3744 return;
3745 }
3746
3747 static int test_type = 0;
3748 static ImGuiTextBuffer log;
3749 static int lines = 0;
3750 ImGui::Text("Printing unusually long amount of text.");
3751 ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0");
3752 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
3753 if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
3754 ImGui::SameLine();
3755 if (ImGui::Button("Add 1000 lines"))
3756 {
3757 for (int i = 0; i < 1000; i++)
3758 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines+i);
3759 lines += 1000;
3760 }
3761 ImGui::BeginChild("Log");
3762 switch (test_type)
3763 {
3764 case 0:
3765 // Single call to TextUnformatted() with a big buffer
3766 ImGui::TextUnformatted(log.begin(), log.end());
3767 break;
3768 case 1:
3769 {
3770 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
3771 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
3772 ImGuiListClipper clipper(lines);
3773 while (clipper.Step())
3774 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
3775 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
3776 ImGui::PopStyleVar();
3777 break;
3778 }
3779 case 2:
3780 // Multiple calls to Text(), not clipped (slow)
3781 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
3782 for (int i = 0; i < lines; i++)
3783 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
3784 ImGui::PopStyleVar();
3785 break;
3786 }
3787 ImGui::EndChild();
3788 ImGui::End();
3789 }
3790
3791 //-----------------------------------------------------------------------------
3792 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
3793 //-----------------------------------------------------------------------------
3794
3795 // Demonstrate creating a window which gets auto-resized according to its content.
3796 static void ShowExampleAppAutoResize(bool* p_open)
3797 {
3798 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
3799 {
3800 ImGui::End();
3801 return;
3802 }
3803
3804 static int lines = 10;
3805 ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop.");
3806 ImGui::SliderInt("Number of lines", &lines, 1, 20);
3807 for (int i = 0; i < lines; i++)
3808 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
3809 ImGui::End();
3810 }
3811
3812 //-----------------------------------------------------------------------------
3813 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
3814 //-----------------------------------------------------------------------------
3815
3816 // Demonstrate creating a window with custom resize constraints.
3817 static void ShowExampleAppConstrainedResize(bool* p_open)
3818 {
3819 struct CustomConstraints // Helper functions to demonstrate programmatic constraints
3820 {
3821 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); }
3822 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); }
3823 };
3824
3825 static bool auto_resize = false;
3826 static int type = 0;
3827 static int display_lines = 10;
3828 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only
3829 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only
3830 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
3831 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500
3832 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500
3833 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
3834 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step
3835
3836 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
3837 if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
3838 {
3839 const char* desc[] =
3840 {
3841 "Resize vertical only",
3842 "Resize horizontal only",
3843 "Width > 100, Height > 100",
3844 "Width 400-500",
3845 "Height 400-500",
3846 "Custom: Always Square",
3847 "Custom: Fixed Steps (100)",
3848 };
3849 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
3850 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
3851 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
3852 ImGui::PushItemWidth(200);
3853 ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc));
3854 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
3855 ImGui::PopItemWidth();
3856 ImGui::Checkbox("Auto-resize", &auto_resize);
3857 for (int i = 0; i < display_lines; i++)
3858 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
3859 }
3860 ImGui::End();
3861 }
3862
3863 //-----------------------------------------------------------------------------
3864 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
3865 //-----------------------------------------------------------------------------
3866
3867 // Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use.
3868 static void ShowExampleAppSimpleOverlay(bool* p_open)
3869 {
3870 const float DISTANCE = 10.0f;
3871 static int corner = 0;
3872 ImGuiIO& io = ImGui::GetIO();
3873 if (corner != -1)
3874 {
3875 ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE);
3876 ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
3877 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
3878 }
3879 ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
3880 if (ImGui::Begin("Example: Simple overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
3881 {
3882 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
3883 ImGui::Separator();
3884 if (ImGui::IsMousePosValid())
3885 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
3886 else
3887 ImGui::Text("Mouse Position: <invalid>");
3888 if (ImGui::BeginPopupContextWindow())
3889 {
3890 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1;
3891 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0;
3892 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1;
3893 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2;
3894 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3;
3895 if (p_open && ImGui::MenuItem("Close")) *p_open = false;
3896 ImGui::EndPopup();
3897 }
3898 }
3899 ImGui::End();
3900 }
3901
3902 //-----------------------------------------------------------------------------
3903 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
3904 //-----------------------------------------------------------------------------
3905
3906 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation.
3907 // This apply to all regular items as well. Read FAQ section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." for details.
3908 static void ShowExampleAppWindowTitles(bool*)
3909 {
3910 // By default, Windows are uniquely identified by their title.
3911 // You can use the "##" and "###" markers to manipulate the display/ID.
3912
3913 // Using "##" to display same title but have unique identifier.
3914 ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
3915 ImGui::Begin("Same title as another window##1");
3916 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
3917 ImGui::End();
3918
3919 ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver);
3920 ImGui::Begin("Same title as another window##2");
3921 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
3922 ImGui::End();
3923
3924 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
3925 char buf[128];
3926 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
3927 ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver);
3928 ImGui::Begin(buf);
3929 ImGui::Text("This window has a changing title.");
3930 ImGui::End();
3931 }
3932
3933 //-----------------------------------------------------------------------------
3934 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
3935 //-----------------------------------------------------------------------------
3936
3937 // Demonstrate using the low-level ImDrawList to draw custom shapes.
3938 static void ShowExampleAppCustomRendering(bool* p_open)
3939 {
3940 ImGui::SetNextWindowSize(ImVec2(350, 560), ImGuiCond_FirstUseEver);
3941 if (!ImGui::Begin("Example: Custom rendering", p_open))
3942 {
3943 ImGui::End();
3944 return;
3945 }
3946
3947 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc.
3948 // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4.
3949 // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types)
3950 // In this example we are not using the maths operators!
3951 ImDrawList* draw_list = ImGui::GetWindowDrawList();
3952
3953 // Primitives
3954 ImGui::Text("Primitives");
3955 static float sz = 36.0f;
3956 static float thickness = 4.0f;
3957 static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
3958 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
3959 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
3960 ImGui::ColorEdit4("Color", &col.x);
3961 {
3962 const ImVec2 p = ImGui::GetCursorScreenPos();
3963 const ImU32 col32 = ImColor(col);
3964 float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f;
3965 for (int n = 0; n < 2; n++)
3966 {
3967 // First line uses a thickness of 1.0, second line uses the configurable thickness
3968 float th = (n == 0) ? 1.0f : thickness;
3969 draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6, th); x += sz+spacing; // Hexagon
3970 draw_list->AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, th); x += sz+spacing; // Circle
3971 draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ImDrawCornerFlags_All, th); x += sz+spacing;
3972 draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_All, th); x += sz+spacing;
3973 draw_list->AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight, th); x += sz+spacing;
3974 draw_list->AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, th); x += sz+spacing;
3975 draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y ), col32, th); x += sz+spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
3976 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y+sz), col32, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
3977 draw_list->AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, th); x += sz+spacing; // Diagonal line
3978 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), col32, th);
3979 x = p.x + 4;
3980 y += sz+spacing;
3981 }
3982 draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 6); x += sz+spacing; // Hexagon
3983 draw_list->AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing; // Circle
3984 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing;
3985 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing;
3986 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotRight); x += sz+spacing;
3987 draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32); x += sz+spacing;
3988 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+thickness), col32); x += sz+spacing; // Horizontal line (faster than AddLine, but only handle integer thickness)
3989 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+thickness, y+sz), col32); x += spacing+spacing; // Vertical line (faster than AddLine, but only handle integer thickness)
3990 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x+1, y+1), col32); x += sz; // Pixel (faster than AddLine)
3991 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));
3992 ImGui::Dummy(ImVec2((sz+spacing)*8, (sz+spacing)*3));
3993 }
3994 ImGui::Separator();
3995 {
3996 static ImVector<ImVec2> points;
3997 static bool adding_line = false;
3998 ImGui::Text("Canvas example");
3999 if (ImGui::Button("Clear")) points.clear();
4000 if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } }
4001 ImGui::Text("Left-click and drag to add lines,\nRight-click to undo");
4002
4003 // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered()
4004 // But you can also draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos().
4005 // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max).
4006 ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
4007 ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
4008 if (canvas_size.x < 50.0f) canvas_size.x = 50.0f;
4009 if (canvas_size.y < 50.0f) canvas_size.y = 50.0f;
4010 draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255));
4011 draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255));
4012
4013 bool adding_preview = false;
4014 ImGui::InvisibleButton("canvas", canvas_size);
4015 ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
4016 if (adding_line)
4017 {
4018 adding_preview = true;
4019 points.push_back(mouse_pos_in_canvas);
4020 if (!ImGui::IsMouseDown(0))
4021 adding_line = adding_preview = false;
4022 }
4023 if (ImGui::IsItemHovered())
4024 {
4025 if (!adding_line && ImGui::IsMouseClicked(0))
4026 {
4027 points.push_back(mouse_pos_in_canvas);
4028 adding_line = true;
4029 }
4030 if (ImGui::IsMouseClicked(1) && !points.empty())
4031 {
4032 adding_line = adding_preview = false;
4033 points.pop_back();
4034 points.pop_back();
4035 }
4036 }
4037 draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true); // clip lines within the canvas (if we resize it, etc.)
4038 for (int i = 0; i < points.Size - 1; i += 2)
4039 draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i + 1].x, canvas_pos.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
4040 draw_list->PopClipRect();
4041 if (adding_preview)
4042 points.pop_back();
4043 }
4044 ImGui::End();
4045 }
4046
4047 //-----------------------------------------------------------------------------
4048 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
4049 //-----------------------------------------------------------------------------
4050
4051 // Simplified structure to mimic a Document model
4052 struct MyDocument
4053 {
4054 const char* Name; // Document title
4055 bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo)
4056 bool OpenPrev; // Copy of Open from last update.
4057 bool Dirty; // Set when the document has been modified
4058 bool WantClose; // Set when the document
4059 ImVec4 Color; // An arbitrary variable associated to the document
4060
4061 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f))
4062 {
4063 Name = name;
4064 Open = OpenPrev = open;
4065 Dirty = false;
4066 WantClose = false;
4067 Color = color;
4068 }
4069 void DoOpen() { Open = true; }
4070 void DoQueueClose() { WantClose = true; }
4071 void DoForceClose() { Open = false; Dirty = false; }
4072 void DoSave() { Dirty = false; }
4073
4074 // Display dummy contents for the Document
4075 static void DisplayContents(MyDocument* doc)
4076 {
4077 ImGui::PushID(doc);
4078 ImGui::Text("Document \"%s\"", doc->Name);
4079 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
4080 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
4081 ImGui::PopStyleColor();
4082 if (ImGui::Button("Modify", ImVec2(100, 0)))
4083 doc->Dirty = true;
4084 ImGui::SameLine();
4085 if (ImGui::Button("Save", ImVec2(100, 0)))
4086 doc->DoSave();
4087 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
4088 ImGui::PopID();
4089 }
4090
4091 // Display context menu for the Document
4092 static void DisplayContextMenu(MyDocument* doc)
4093 {
4094 if (!ImGui::BeginPopupContextItem())
4095 return;
4096
4097 char buf[256];
4098 sprintf(buf, "Save %s", doc->Name);
4099 if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open))
4100 doc->DoSave();
4101 if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open))
4102 doc->DoQueueClose();
4103 ImGui::EndPopup();
4104 }
4105 };
4106
4107 struct ExampleAppDocuments
4108 {
4109 ImVector<MyDocument> Documents;
4110
4111 ExampleAppDocuments()
4112 {
4113 Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
4114 Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
4115 Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
4116 Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
4117 Documents.push_back(MyDocument("A Rather Long Title", false));
4118 Documents.push_back(MyDocument("Some Document", false));
4119 }
4120 };
4121
4122 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
4123 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed
4124 // to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence.
4125 // During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar
4126 // will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame.
4127 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
4128 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
4129 static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
4130 {
4131 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
4132 {
4133 MyDocument* doc = &app.Documents[doc_n];
4134 if (!doc->Open && doc->OpenPrev)
4135 ImGui::SetTabItemClosed(doc->Name);
4136 doc->OpenPrev = doc->Open;
4137 }
4138 }
4139
4140 void ShowExampleAppDocuments(bool* p_open)
4141 {
4142 static ExampleAppDocuments app;
4143
4144 if (!ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar))
4145 {
4146 ImGui::End();
4147 return;
4148 }
4149
4150 // Options
4151 static bool opt_reorderable = true;
4152 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
4153
4154 // Menu
4155 if (ImGui::BeginMenuBar())
4156 {
4157 if (ImGui::BeginMenu("File"))
4158 {
4159 int open_count = 0;
4160 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
4161 open_count += app.Documents[doc_n].Open ? 1 : 0;
4162
4163 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
4164 {
4165 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
4166 {
4167 MyDocument* doc = &app.Documents[doc_n];
4168 if (!doc->Open)
4169 if (ImGui::MenuItem(doc->Name))
4170 doc->DoOpen();
4171 }
4172 ImGui::EndMenu();
4173 }
4174 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
4175 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
4176 app.Documents[doc_n].DoQueueClose();
4177 if (ImGui::MenuItem("Exit", "Alt+F4")) {}
4178 ImGui::EndMenu();
4179 }
4180 ImGui::EndMenuBar();
4181 }
4182
4183 // [Debug] List documents with one checkbox for each
4184 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
4185 {
4186 MyDocument* doc = &app.Documents[doc_n];
4187 if (doc_n > 0)
4188 ImGui::SameLine();
4189 ImGui::PushID(doc);
4190 if (ImGui::Checkbox(doc->Name, &doc->Open))
4191 if (!doc->Open)
4192 doc->DoForceClose();
4193 ImGui::PopID();
4194 }
4195
4196 ImGui::Separator();
4197
4198 // Submit Tab Bar and Tabs
4199 {
4200 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
4201 if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
4202 {
4203 if (opt_reorderable)
4204 NotifyOfDocumentsClosedElsewhere(app);
4205
4206 // [DEBUG] Stress tests
4207 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
4208 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
4209
4210 // Submit Tabs
4211 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
4212 {
4213 MyDocument* doc = &app.Documents[doc_n];
4214 if (!doc->Open)
4215 continue;
4216
4217 ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
4218 bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags);
4219
4220 // Cancel attempt to close when unsaved add to save queue so we can display a popup.
4221 if (!doc->Open && doc->Dirty)
4222 {
4223 doc->Open = true;
4224 doc->DoQueueClose();
4225 }
4226
4227 MyDocument::DisplayContextMenu(doc);
4228 if (visible)
4229 {
4230 MyDocument::DisplayContents(doc);
4231 ImGui::EndTabItem();
4232 }
4233 }
4234
4235 ImGui::EndTabBar();
4236 }
4237 }
4238
4239 // Update closing queue
4240 static ImVector<MyDocument*> close_queue;
4241 if (close_queue.empty())
4242 {
4243 // Close queue is locked once we started a popup
4244 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
4245 {
4246 MyDocument* doc = &app.Documents[doc_n];
4247 if (doc->WantClose)
4248 {
4249 doc->WantClose = false;
4250 close_queue.push_back(doc);
4251 }
4252 }
4253 }
4254
4255 // Display closing confirmation UI
4256 if (!close_queue.empty())
4257 {
4258 int close_queue_unsaved_documents = 0;
4259 for (int n = 0; n < close_queue.Size; n++)
4260 if (close_queue[n]->Dirty)
4261 close_queue_unsaved_documents++;
4262
4263 if (close_queue_unsaved_documents == 0)
4264 {
4265 // Close documents when all are unsaved
4266 for (int n = 0; n < close_queue.Size; n++)
4267 close_queue[n]->DoForceClose();
4268 close_queue.clear();
4269 }
4270 else
4271 {
4272 if (!ImGui::IsPopupOpen("Save?"))
4273 ImGui::OpenPopup("Save?");
4274 if (ImGui::BeginPopupModal("Save?"))
4275 {
4276 ImGui::Text("Save change to the following items?");
4277 ImGui::PushItemWidth(-1.0f);
4278 ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6);
4279 for (int n = 0; n < close_queue.Size; n++)
4280 if (close_queue[n]->Dirty)
4281 ImGui::Text("%s", close_queue[n]->Name);
4282 ImGui::ListBoxFooter();
4283
4284 if (ImGui::Button("Yes", ImVec2(80, 0)))
4285 {
4286 for (int n = 0; n < close_queue.Size; n++)
4287 {
4288 if (close_queue[n]->Dirty)
4289 close_queue[n]->DoSave();
4290 close_queue[n]->DoForceClose();
4291 }
4292 close_queue.clear();
4293 ImGui::CloseCurrentPopup();
4294 }
4295 ImGui::SameLine();
4296 if (ImGui::Button("No", ImVec2(80, 0)))
4297 {
4298 for (int n = 0; n < close_queue.Size; n++)
4299 close_queue[n]->DoForceClose();
4300 close_queue.clear();
4301 ImGui::CloseCurrentPopup();
4302 }
4303 ImGui::SameLine();
4304 if (ImGui::Button("Cancel", ImVec2(80, 0)))
4305 {
4306 close_queue.clear();
4307 ImGui::CloseCurrentPopup();
4308 }
4309 ImGui::EndPopup();
4310 }
4311 }
4312 }
4313
4314 ImGui::End();
4315 }
4316
4317 // End of Demo code
4318 #else
4319
4320 void ImGui::ShowAboutWindow(bool*) {}
4321 void ImGui::ShowDemoWindow(bool*) {}
4322 void ImGui::ShowUserGuide() {}
4323 void ImGui::ShowStyleEditor(ImGuiStyle*) {}
4324
4325 #endif