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