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