1 // dear imgui, v1.60 WIP
2 // (demo code)
3
4 // Message to the person tempted to delete this file when integrating ImGui into their code base:
5 // Don't do it! Do NOT remove this file from your project! It is useful reference code that you and other users will want to refer to.
6 // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
7 // During development, you can call ImGui::ShowDemoWindow() in your code to learn about various features of ImGui. Have it wired in a debug menu!
8 // Removing this file from your project is hindering access to documentation for everyone in your team, likely leading you to poorer usage of the library.
9 // Note that you can #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h for the same effect.
10 // If you want to link core ImGui in your final builds but not those demo windows, #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h and those functions will be empty.
11 // In other situation, when you have ImGui available you probably want this to be available for reference and execution.
12 // Thank you,
13 // -Your beloved friend, imgui_demo.cpp (that you won't delete)
14
15 // Message to beginner C/C++ programmers. About the meaning of 'static': in this demo code, we frequently we use 'static' variables inside functions.
16 // We do this as a way to gather code and data in the same place, just to make the demo code faster to read, faster to write, and use less code.
17 // A static variable persist across calls, so it is essentially like a global variable but declared inside the scope of the function.
18 // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant or used in threads.
19 // This might be a pattern you occasionally want to use in your code, but most of the real data you would be editing is likely to be stored outside your function.
20
21 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
22 #define _CRT_SECURE_NO_WARNINGS
23 #endif
24
25 #include "imgui.h"
26 #include <ctype.h> // toupper, isprint
27 #include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf
28 #include <stdio.h> // vsnprintf, sscanf, printf
29 #include <stdlib.h> // NULL, malloc, free, atoi
30 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
31 #include <stddef.h> // intptr_t
32 #else
33 #include <stdint.h> // intptr_t
34 #endif
35
36 #ifdef _MSC_VER
37 #pragma warning(disable : 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
38 #define snprintf _snprintf
39 #endif
40 #ifdef __clang__
41 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
42 #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)
43 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
44 #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal
45 #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.
46 #if __has_warning("-Wreserved-id-macro")
47 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
48 #endif
49 #elif defined(__GNUC__)
50 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
51 #pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure)
52 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
53 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
54 #if (__GNUC__ >= 6)
55 #pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub.
56 #endif
57 #endif
58
59 // Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n.
60 #ifdef _WIN32
61 #define IM_NEWLINE "\r\n"
62 #else
63 #define IM_NEWLINE "\n"
64 #endif
65
66 #define IM_MAX(_A, _B) (((_A) >= (_B)) ? (_A) : (_B))
67
68 //-----------------------------------------------------------------------------
69 // DEMO CODE
70 //-----------------------------------------------------------------------------
71
72 #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Obsolete name since 1.53, TEST->DEMO
73 #define IMGUI_DISABLE_DEMO_WINDOWS
74 #endif
75
76 #if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
77
78 static void ShowExampleAppConsole(bool* p_open);
79 static void ShowExampleAppLog(bool* p_open);
80 static void ShowExampleAppLayout(bool* p_open);
81 static void ShowExampleAppPropertyEditor(bool* p_open);
82 static void ShowExampleAppLongText(bool* p_open);
83 static void ShowExampleAppAutoResize(bool* p_open);
84 static void ShowExampleAppConstrainedResize(bool* p_open);
85 static void ShowExampleAppFixedOverlay(bool* p_open);
86 static void ShowExampleAppWindowTitles(bool* p_open);
87 static void ShowExampleAppCustomRendering(bool* p_open);
88 static void ShowExampleAppMainMenuBar();
89 static void ShowExampleMenuFile();
90
ShowHelpMarker(const char * desc)91 static void ShowHelpMarker(const char* desc)
92 {
93 ImGui::TextDisabled("(?)");
94 if (ImGui::IsItemHovered())
95 {
96 ImGui::BeginTooltip();
97 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
98 ImGui::TextUnformatted(desc);
99 ImGui::PopTextWrapPos();
100 ImGui::EndTooltip();
101 }
102 }
103
ShowUserGuide()104 void ImGui::ShowUserGuide()
105 {
106 ImGui::BulletText("Double-click on title bar to collapse window.");
107 ImGui::BulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents).");
108 ImGui::BulletText("Click and drag on any empty space to move window.");
109 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
110 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
111 if (ImGui::GetIO().FontAllowUserScaling)
112 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
113 ImGui::BulletText("Mouse Wheel to scroll.");
114 ImGui::BulletText("While editing text:\n");
115 ImGui::Indent();
116 ImGui::BulletText("Hold SHIFT or use mouse to select text.");
117 ImGui::BulletText("CTRL+Left/Right to word jump.");
118 ImGui::BulletText("CTRL+A or double-click to select all.");
119 ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard.");
120 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
121 ImGui::BulletText("ESCAPE to revert.");
122 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
123 ImGui::Unindent();
124 }
125
126 // Demonstrate most ImGui features (big function!)
ShowDemoWindow(bool * p_open)127 void ImGui::ShowDemoWindow(bool* p_open)
128 {
129 // Examples apps
130 static bool show_app_main_menu_bar = false;
131 static bool show_app_console = false;
132 static bool show_app_log = false;
133 static bool show_app_layout = false;
134 static bool show_app_property_editor = false;
135 static bool show_app_long_text = false;
136 static bool show_app_auto_resize = false;
137 static bool show_app_constrained_resize = false;
138 static bool show_app_fixed_overlay = false;
139 static bool show_app_window_titles = false;
140 static bool show_app_custom_rendering = false;
141 static bool show_app_style_editor = false;
142
143 static bool show_app_metrics = false;
144 static bool show_app_about = false;
145
146 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
147 if (show_app_console) ShowExampleAppConsole(&show_app_console);
148 if (show_app_log) ShowExampleAppLog(&show_app_log);
149 if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
150 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
151 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
152 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
153 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
154 if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay);
155 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
156 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
157
158 if (show_app_metrics)
159 {
160 ImGui::ShowMetricsWindow(&show_app_metrics);
161 }
162 if (show_app_style_editor)
163 {
164 ImGui::Begin("Style Editor", &show_app_style_editor);
165 ImGui::ShowStyleEditor();
166 ImGui::End();
167 }
168 if (show_app_about)
169 {
170 ImGui::Begin("About Dear ImGui", &show_app_about, ImGuiWindowFlags_AlwaysAutoResize);
171 ImGui::Text("Dear ImGui, %s", ImGui::GetVersion());
172 ImGui::Separator();
173 ImGui::Text("By Omar Cornut and all dear imgui contributors.");
174 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
175 ImGui::End();
176 }
177
178 static bool no_titlebar = false;
179 static bool no_scrollbar = false;
180 static bool no_menu = false;
181 static bool no_move = false;
182 static bool no_resize = false;
183 static bool no_collapse = false;
184 static bool no_close = false;
185 static bool no_nav = false;
186
187 // Demonstrate the various window flags. Typically you would just use the default.
188 ImGuiWindowFlags window_flags = 0;
189 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
190 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
191 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar;
192 if (no_move) window_flags |= ImGuiWindowFlags_NoMove;
193 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
194 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
195 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
196 if (no_close) p_open = NULL; // Don't pass our bool* to Begin
197
198 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
199 if (!ImGui::Begin("ImGui Demo", p_open, window_flags))
200 {
201 // Early out if the window is collapsed, as an optimization.
202 ImGui::End();
203 return;
204 }
205
206 //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // 2/3 of the space for widget and 1/3 for labels
207 ImGui::PushItemWidth(-140); // Right align, keep 140 pixels for labels
208
209 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION);
210
211 // Menu
212 if (ImGui::BeginMenuBar())
213 {
214 if (ImGui::BeginMenu("Menu"))
215 {
216 ShowExampleMenuFile();
217 ImGui::EndMenu();
218 }
219 if (ImGui::BeginMenu("Examples"))
220 {
221 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
222 ImGui::MenuItem("Console", NULL, &show_app_console);
223 ImGui::MenuItem("Log", NULL, &show_app_log);
224 ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
225 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
226 ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
227 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
228 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
229 ImGui::MenuItem("Simple overlay", NULL, &show_app_fixed_overlay);
230 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
231 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
232 ImGui::EndMenu();
233 }
234 if (ImGui::BeginMenu("Help"))
235 {
236 ImGui::MenuItem("Metrics", NULL, &show_app_metrics);
237 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
238 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
239 ImGui::EndMenu();
240 }
241 ImGui::EndMenuBar();
242 }
243
244 ImGui::Spacing();
245 if (ImGui::CollapsingHeader("Help"))
246 {
247 ImGui::TextWrapped("This window is being created by the ShowDemoWindow() function. Please refer to the code in imgui_demo.cpp for reference.\n\n");
248 ImGui::Text("USER GUIDE:");
249 ImGui::ShowUserGuide();
250 }
251
252 if (ImGui::CollapsingHeader("Window options"))
253 {
254 ImGui::Checkbox("No titlebar", &no_titlebar);
255 ImGui::SameLine(150);
256 ImGui::Checkbox("No scrollbar", &no_scrollbar);
257 ImGui::SameLine(300);
258 ImGui::Checkbox("No menu", &no_menu);
259 ImGui::Checkbox("No move", &no_move);
260 ImGui::SameLine(150);
261 ImGui::Checkbox("No resize", &no_resize);
262 ImGui::SameLine(300);
263 ImGui::Checkbox("No collapse", &no_collapse);
264 ImGui::Checkbox("No close", &no_close);
265 ImGui::SameLine(150);
266 ImGui::Checkbox("No nav", &no_nav);
267
268 if (ImGui::TreeNode("Style"))
269 {
270 ImGui::ShowStyleEditor();
271 ImGui::TreePop();
272 }
273
274 if (ImGui::TreeNode("Capture/Logging"))
275 {
276 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. You can also call ImGui::LogText() to output directly to the log without a visual output.");
277 ImGui::LogButtons();
278 ImGui::TreePop();
279 }
280 }
281
282 if (ImGui::CollapsingHeader("Widgets"))
283 {
284 if (ImGui::TreeNode("Basic"))
285 {
286 static int clicked = 0;
287 if (ImGui::Button("Button"))
288 clicked++;
289 if (clicked & 1)
290 {
291 ImGui::SameLine();
292 ImGui::Text("Thanks for clicking me!");
293 }
294
295 static bool check = true;
296 ImGui::Checkbox("checkbox", &check);
297
298 static int e = 0;
299 ImGui::RadioButton("radio a", &e, 0);
300 ImGui::SameLine();
301 ImGui::RadioButton("radio b", &e, 1);
302 ImGui::SameLine();
303 ImGui::RadioButton("radio c", &e, 2);
304
305 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
306 for (int i = 0; i < 7; i++)
307 {
308 if (i > 0) ImGui::SameLine();
309 ImGui::PushID(i);
310 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
311 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
312 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
313 ImGui::Button("Click");
314 ImGui::PopStyleColor(3);
315 ImGui::PopID();
316 }
317
318 ImGui::Text("Hover over me");
319 if (ImGui::IsItemHovered())
320 ImGui::SetTooltip("I am a tooltip");
321
322 ImGui::SameLine();
323 ImGui::Text("- or me");
324 if (ImGui::IsItemHovered())
325 {
326 ImGui::BeginTooltip();
327 ImGui::Text("I am a fancy tooltip");
328 static float arr[] = {0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f};
329 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
330 ImGui::EndTooltip();
331 }
332
333 // Testing ImGuiOnceUponAFrame helper.
334 //static ImGuiOnceUponAFrame once;
335 //for (int i = 0; i < 5; i++)
336 // if (once)
337 // ImGui::Text("This will be displayed only once.");
338
339 ImGui::Separator();
340
341 ImGui::LabelText("label", "Value");
342
343 {
344 // Simplified one-liner Combo() API, using values packed in a single constant string
345 static int current_item_1 = 1;
346 ImGui::Combo("combo", ¤t_item_1, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
347 //ImGui::Combo("combo w/ array of char*", ¤t_item_2_idx, items, IM_ARRAYSIZE(items)); // Combo using proper array. You can also pass a callback to retrieve array value, no need to create/copy an array just for that.
348
349 // General BeginCombo() API, you have full control over your selection data and display type
350 const char* items[] = {"AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO", "PPPP", "QQQQQQQQQQ", "RRR", "SSSS"};
351 static const char* current_item_2 = NULL;
352 if (ImGui::BeginCombo("combo 2", current_item_2)) // The second parameter is the label previewed before opening the combo.
353 {
354 for (int n = 0; n < IM_ARRAYSIZE(items); n++)
355 {
356 bool is_selected = (current_item_2 == items[n]); // You can store your selection however you want, outside or inside your objects
357 if (ImGui::Selectable(items[n], is_selected))
358 current_item_2 = items[n];
359 if (is_selected)
360 ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
361 }
362 ImGui::EndCombo();
363 }
364 }
365
366 {
367 static char str0[128] = "Hello, world!";
368 static int i0 = 123;
369 static float f0 = 0.001f;
370 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
371 ImGui::SameLine();
372 ShowHelpMarker(
373 "Hold SHIFT or use mouse to select text.\n"
374 "CTRL+Left/Right to word jump.\n"
375 "CTRL+A or double-click to select all.\n"
376 "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
377 "CTRL+Z,CTRL+Y undo/redo.\n"
378 "ESCAPE to revert.\n");
379
380 ImGui::InputInt("input int", &i0);
381 ImGui::SameLine();
382 ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n");
383
384 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f);
385
386 static float vec4a[4] = {0.10f, 0.20f, 0.30f, 0.44f};
387 ImGui::InputFloat3("input float3", vec4a);
388 }
389
390 {
391 static int i1 = 50, i2 = 42;
392 ImGui::DragInt("drag int", &i1, 1);
393 ImGui::SameLine();
394 ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value.");
395
396 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%");
397
398 static float f1 = 1.00f, f2 = 0.0067f;
399 ImGui::DragFloat("drag float", &f1, 0.005f);
400 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
401 }
402
403 {
404 static int i1 = 0;
405 ImGui::SliderInt("slider int", &i1, -1, 3);
406 ImGui::SameLine();
407 ShowHelpMarker("CTRL+click to input value.");
408
409 static float f1 = 0.123f, f2 = 0.0f;
410 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
411 ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f);
412 static float angle = 0.0f;
413 ImGui::SliderAngle("slider angle", &angle);
414 }
415
416 static float col1[3] = {1.0f, 0.0f, 0.2f};
417 static float col2[4] = {0.4f, 0.7f, 0.0f, 0.5f};
418 ImGui::ColorEdit3("color 1", col1);
419 ImGui::SameLine();
420 ShowHelpMarker("Click on the colored square to open a color picker.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n");
421
422 ImGui::ColorEdit4("color 2", col2);
423
424 const char* listbox_items[] = {"Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon"};
425 static int listbox_item_current = 1;
426 ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
427
428 //static int listbox_item_current2 = 2;
429 //ImGui::PushItemWidth(-1);
430 //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
431 //ImGui::PopItemWidth();
432
433 ImGui::TreePop();
434 }
435
436 if (ImGui::TreeNode("Trees"))
437 {
438 if (ImGui::TreeNode("Basic trees"))
439 {
440 for (int i = 0; i < 5; i++)
441 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
442 {
443 ImGui::Text("blah blah");
444 ImGui::SameLine();
445 if (ImGui::SmallButton("button"))
446 {
447 };
448 ImGui::TreePop();
449 }
450 ImGui::TreePop();
451 }
452
453 if (ImGui::TreeNode("Advanced, with Selectable nodes"))
454 {
455 ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open.");
456 static bool align_label_with_current_x_position = false;
457 ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position);
458 ImGui::Text("Hello!");
459 if (align_label_with_current_x_position)
460 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
461
462 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.
463 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.
464 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize() * 3); // Increase spacing to differentiate leaves from expanded contents.
465 for (int i = 0; i < 6; i++)
466 {
467 // Disable the default open on single-click behavior and pass in Selected flag according to our selection state.
468 ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0);
469 if (i < 3)
470 {
471 // Node
472 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
473 if (ImGui::IsItemClicked())
474 node_clicked = i;
475 if (node_open)
476 {
477 ImGui::Text("Blah blah\nBlah Blah");
478 ImGui::TreePop();
479 }
480 }
481 else
482 {
483 // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text().
484 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
485 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
486 if (ImGui::IsItemClicked())
487 node_clicked = i;
488 }
489 }
490 if (node_clicked != -1)
491 {
492 // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.
493 if (ImGui::GetIO().KeyCtrl)
494 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle
495 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
496 selection_mask = (1 << node_clicked); // Click to single-select
497 }
498 ImGui::PopStyleVar();
499 if (align_label_with_current_x_position)
500 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
501 ImGui::TreePop();
502 }
503 ImGui::TreePop();
504 }
505
506 if (ImGui::TreeNode("Collapsing Headers"))
507 {
508 static bool closable_group = true;
509 ImGui::Checkbox("Enable extra group", &closable_group);
510 if (ImGui::CollapsingHeader("Header"))
511 {
512 ImGui::Text("IsItemHovered: %d", IsItemHovered());
513 for (int i = 0; i < 5; i++)
514 ImGui::Text("Some content %d", i);
515 }
516 if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
517 {
518 ImGui::Text("IsItemHovered: %d", IsItemHovered());
519 for (int i = 0; i < 5; i++)
520 ImGui::Text("More content %d", i);
521 }
522 ImGui::TreePop();
523 }
524
525 if (ImGui::TreeNode("Bullets"))
526 {
527 ImGui::BulletText("Bullet point 1");
528 ImGui::BulletText("Bullet point 2\nOn multiple lines");
529 ImGui::Bullet();
530 ImGui::Text("Bullet point 3 (two calls)");
531 ImGui::Bullet();
532 ImGui::SmallButton("Button");
533 ImGui::TreePop();
534 }
535
536 if (ImGui::TreeNode("Text"))
537 {
538 if (ImGui::TreeNode("Colored Text"))
539 {
540 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
541 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
542 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
543 ImGui::TextDisabled("Disabled");
544 ImGui::SameLine();
545 ShowHelpMarker("The TextDisabled color is stored in ImGuiStyle.");
546 ImGui::TreePop();
547 }
548
549 if (ImGui::TreeNode("Word Wrapping"))
550 {
551 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
552 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.");
553 ImGui::Spacing();
554
555 static float wrap_width = 200.0f;
556 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
557
558 ImGui::Text("Test paragraph 1:");
559 ImVec2 pos = ImGui::GetCursorScreenPos();
560 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));
561 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
562 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);
563 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
564 ImGui::PopTextWrapPos();
565
566 ImGui::Text("Test paragraph 2:");
567 pos = ImGui::GetCursorScreenPos();
568 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));
569 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
570 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh");
571 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
572 ImGui::PopTextWrapPos();
573
574 ImGui::TreePop();
575 }
576
577 if (ImGui::TreeNode("UTF-8 Text"))
578 {
579 // UTF-8 test with Japanese characters
580 // (needs a suitable font, try Arial Unicode or M+ fonts http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html)
581 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
582 // - 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')
583 // - HOWEVER, FOR THIS DEMO FILE, BECAUSE WE WANT TO SUPPORT COMPILER, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE.
584 // Instead we are encoding a few string with hexadecimal constants. Don't do this in your application!
585 // 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.
586 ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to load extra character ranges.");
587 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
588 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
589 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; // "nihongo"
590 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
591 ImGui::TreePop();
592 }
593 ImGui::TreePop();
594 }
595
596 if (ImGui::TreeNode("Images"))
597 {
598 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!");
599 ImGuiIO& io = ImGui::GetIO();
600
601 // Here we are grabbing the font texture because that's the only one we have access to inside the demo code.
602 // 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.
603 // 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.
604 // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_glfw_gl3.cpp renderer expect a GLuint OpenGL texture identifier etc.)
605 // 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.
606 // 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.
607 // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
608 ImTextureID my_tex_id = io.Fonts->TexID;
609 float my_tex_w = (float)io.Fonts->TexWidth;
610 float my_tex_h = (float)io.Fonts->TexHeight;
611
612 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
613 ImVec2 pos = ImGui::GetCursorScreenPos();
614 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
615 if (ImGui::IsItemHovered())
616 {
617 ImGui::BeginTooltip();
618 float focus_sz = 32.0f;
619 float focus_x = io.MousePos.x - pos.x - focus_sz * 0.5f;
620 if (focus_x < 0.0f)
621 focus_x = 0.0f;
622 else if (focus_x > my_tex_w - focus_sz)
623 focus_x = my_tex_w - focus_sz;
624 float focus_y = io.MousePos.y - pos.y - focus_sz * 0.5f;
625 if (focus_y < 0.0f)
626 focus_y = 0.0f;
627 else if (focus_y > my_tex_h - focus_sz)
628 focus_y = my_tex_h - focus_sz;
629 ImGui::Text("Min: (%.2f, %.2f)", focus_x, focus_y);
630 ImGui::Text("Max: (%.2f, %.2f)", focus_x + focus_sz, focus_y + focus_sz);
631 ImVec2 uv0 = ImVec2((focus_x) / my_tex_w, (focus_y) / my_tex_h);
632 ImVec2 uv1 = ImVec2((focus_x + focus_sz) / my_tex_w, (focus_y + focus_sz) / my_tex_h);
633 ImGui::Image(my_tex_id, ImVec2(128, 128), uv0, uv1, ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
634 ImGui::EndTooltip();
635 }
636 ImGui::TextWrapped("And now some textured buttons..");
637 static int pressed_count = 0;
638 for (int i = 0; i < 8; i++)
639 {
640 ImGui::PushID(i);
641 int frame_padding = -1 + i; // -1 = uses default padding
642 if (ImGui::ImageButton(my_tex_id, ImVec2(32, 32), ImVec2(0, 0), ImVec2(32.0f / my_tex_w, 32 / my_tex_h), frame_padding, ImColor(0, 0, 0, 255)))
643 pressed_count += 1;
644 ImGui::PopID();
645 ImGui::SameLine();
646 }
647 ImGui::NewLine();
648 ImGui::Text("Pressed %d times.", pressed_count);
649 ImGui::TreePop();
650 }
651
652 if (ImGui::TreeNode("Selectables"))
653 {
654 // Selectable() has 2 overloads:
655 // - 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.
656 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
657 // 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).
658 if (ImGui::TreeNode("Basic"))
659 {
660 static bool selection[5] = {false, true, false, false, false};
661 ImGui::Selectable("1. I am selectable", &selection[0]);
662 ImGui::Selectable("2. I am selectable", &selection[1]);
663 ImGui::Text("3. I am not selectable");
664 ImGui::Selectable("4. I am selectable", &selection[3]);
665 if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick))
666 if (ImGui::IsMouseDoubleClicked(0))
667 selection[4] = !selection[4];
668 ImGui::TreePop();
669 }
670 if (ImGui::TreeNode("Selection State: Single Selection"))
671 {
672 static int selected = -1;
673 for (int n = 0; n < 5; n++)
674 {
675 char buf[32];
676 sprintf(buf, "Object %d", n);
677 if (ImGui::Selectable(buf, selected == n))
678 selected = n;
679 }
680 ImGui::TreePop();
681 }
682 if (ImGui::TreeNode("Selection State: Multiple Selection"))
683 {
684 ShowHelpMarker("Hold CTRL and click to select multiple items.");
685 static bool selection[5] = {false, false, false, false, false};
686 for (int n = 0; n < 5; n++)
687 {
688 char buf[32];
689 sprintf(buf, "Object %d", n);
690 if (ImGui::Selectable(buf, selection[n]))
691 {
692 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
693 memset(selection, 0, sizeof(selection));
694 selection[n] ^= 1;
695 }
696 }
697 ImGui::TreePop();
698 }
699 if (ImGui::TreeNode("Rendering more text into the same line"))
700 {
701 // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically.
702 static bool selected[3] = {false, false, false};
703 ImGui::Selectable("main.c", &selected[0]);
704 ImGui::SameLine(300);
705 ImGui::Text(" 2,345 bytes");
706 ImGui::Selectable("Hello.cpp", &selected[1]);
707 ImGui::SameLine(300);
708 ImGui::Text("12,345 bytes");
709 ImGui::Selectable("Hello.h", &selected[2]);
710 ImGui::SameLine(300);
711 ImGui::Text(" 2,345 bytes");
712 ImGui::TreePop();
713 }
714 if (ImGui::TreeNode("In columns"))
715 {
716 ImGui::Columns(3, NULL, false);
717 static bool selected[16] = {0};
718 for (int i = 0; i < 16; i++)
719 {
720 char label[32];
721 sprintf(label, "Item %d", i);
722 if (ImGui::Selectable(label, &selected[i]))
723 {
724 }
725 ImGui::NextColumn();
726 }
727 ImGui::Columns(1);
728 ImGui::TreePop();
729 }
730 if (ImGui::TreeNode("Grid"))
731 {
732 static bool selected[16] = {true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true};
733 for (int i = 0; i < 16; i++)
734 {
735 ImGui::PushID(i);
736 if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50, 50)))
737 {
738 int x = i % 4, y = i / 4;
739 if (x > 0) selected[i - 1] ^= 1;
740 if (x < 3) selected[i + 1] ^= 1;
741 if (y > 0) selected[i - 4] ^= 1;
742 if (y < 3) selected[i + 4] ^= 1;
743 }
744 if ((i % 4) < 3) ImGui::SameLine();
745 ImGui::PopID();
746 }
747 ImGui::TreePop();
748 }
749 ImGui::TreePop();
750 }
751
752 if (ImGui::TreeNode("Filtered Text Input"))
753 {
754 static char buf1[64] = "";
755 ImGui::InputText("default", buf1, 64);
756 static char buf2[64] = "";
757 ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal);
758 static char buf3[64] = "";
759 ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
760 static char buf4[64] = "";
761 ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase);
762 static char buf5[64] = "";
763 ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank);
764 struct TextFilters
765 {
766 static int FilterImGuiLetters(ImGuiTextEditCallbackData* data)
767 {
768 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0;
769 return 1;
770 }
771 };
772 static char buf6[64] = "";
773 ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters);
774
775 ImGui::Text("Password input");
776 static char bufpass[64] = "password123";
777 ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank);
778 ImGui::SameLine();
779 ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
780 ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank);
781
782 ImGui::TreePop();
783 }
784
785 if (ImGui::TreeNode("Multi-line Text Input"))
786 {
787 static bool read_only = false;
788 static char text[1024 * 16] =
789 "/*\n"
790 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
791 " the hexadecimal encoding of one offending instruction,\n"
792 " more formally, the invalid operand with locked CMPXCHG8B\n"
793 " instruction bug, is a design flaw in the majority of\n"
794 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
795 " processors (all in the P5 microarchitecture).\n"
796 "*/\n\n"
797 "label:\n"
798 "\tlock cmpxchg8b eax\n";
799
800 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
801 ImGui::Checkbox("Read-only", &read_only);
802 ImGui::PopStyleVar();
803 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0));
804 ImGui::TreePop();
805 }
806
807 if (ImGui::TreeNode("Plots widgets"))
808 {
809 static bool animate = true;
810 ImGui::Checkbox("Animate", &animate);
811
812 static float arr[] = {0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f};
813 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
814
815 // Create a dummy array of contiguous float values to plot
816 // 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.
817 static float values[90] = {0};
818 static int values_offset = 0;
819 static float refresh_time = 0.0f;
820 if (!animate || refresh_time == 0.0f)
821 refresh_time = ImGui::GetTime();
822 while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo
823 {
824 static float phase = 0.0f;
825 values[values_offset] = cosf(phase);
826 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
827 phase += 0.10f * values_offset;
828 refresh_time += 1.0f / 60.0f;
829 }
830 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0, 80));
831 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80));
832
833 // Use functions to generate output
834 // 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.
835 struct Funcs
836 {
837 static float Sin(void*, int i) { return sinf(i * 0.1f); }
838 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
839 };
840 static int func_type = 0, display_count = 70;
841 ImGui::Separator();
842 ImGui::PushItemWidth(100);
843 ImGui::Combo("func", &func_type, "Sin\0Saw\0");
844 ImGui::PopItemWidth();
845 ImGui::SameLine();
846 ImGui::SliderInt("Sample count", &display_count, 1, 400);
847 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
848 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
849 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
850 ImGui::Separator();
851
852 // Animate a simple progress bar
853 static float progress = 0.0f, progress_dir = 1.0f;
854 if (animate)
855 {
856 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
857 if (progress >= +1.1f)
858 {
859 progress = +1.1f;
860 progress_dir *= -1.0f;
861 }
862 if (progress <= -0.1f)
863 {
864 progress = -0.1f;
865 progress_dir *= -1.0f;
866 }
867 }
868
869 // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
870 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
871 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
872 ImGui::Text("Progress Bar");
873
874 float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress;
875 char buf[32];
876 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
877 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
878 ImGui::TreePop();
879 }
880
881 if (ImGui::TreeNode("Color/Picker Widgets"))
882 {
883 static ImVec4 color = ImColor(114, 144, 154, 200);
884
885 static bool alpha_preview = true;
886 static bool alpha_half_preview = false;
887 static bool options_menu = true;
888 static bool hdr = false;
889 ImGui::Checkbox("With Alpha Preview", &alpha_preview);
890 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
891 ImGui::Checkbox("With Options Menu", &options_menu);
892 ImGui::SameLine();
893 ShowHelpMarker("Right-click on the individual color widget to show options.");
894 ImGui::Checkbox("With HDR", &hdr);
895 ImGui::SameLine();
896 ShowHelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
897 int misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
898
899 ImGui::Text("Color widget:");
900 ImGui::SameLine();
901 ShowHelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n");
902 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
903
904 ImGui::Text("Color widget HSV with Alpha:");
905 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_HSV | misc_flags);
906
907 ImGui::Text("Color widget with Float Display:");
908 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
909
910 ImGui::Text("Color button with Picker:");
911 ImGui::SameLine();
912 ShowHelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup.");
913 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
914
915 ImGui::Text("Color button with Custom Picker Popup:");
916
917 // Generate a dummy palette
918 static bool saved_palette_inited = false;
919 static ImVec4 saved_palette[32];
920 if (!saved_palette_inited)
921 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
922 {
923 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
924 saved_palette[n].w = 1.0f; // Alpha
925 }
926 saved_palette_inited = true;
927
928 static ImVec4 backup_color;
929 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
930 ImGui::SameLine();
931 open_popup |= ImGui::Button("Palette");
932 if (open_popup)
933 {
934 ImGui::OpenPopup("mypicker");
935 backup_color = color;
936 }
937 if (ImGui::BeginPopup("mypicker"))
938 {
939 // FIXME: Adding a drag and drop example here would be perfect!
940 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
941 ImGui::Separator();
942 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
943 ImGui::SameLine();
944 ImGui::BeginGroup();
945 ImGui::Text("Current");
946 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
947 ImGui::Text("Previous");
948 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
949 color = backup_color;
950 ImGui::Separator();
951 ImGui::Text("Palette");
952 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
953 {
954 ImGui::PushID(n);
955 if ((n % 8) != 0)
956 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
957 if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20)))
958 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
959
960 if (ImGui::BeginDragDropTarget())
961 {
962 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
963 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
964 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
965 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
966 EndDragDropTarget();
967 }
968
969 ImGui::PopID();
970 }
971 ImGui::EndGroup();
972 ImGui::EndPopup();
973 }
974
975 ImGui::Text("Color button only:");
976 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags, ImVec2(80, 80));
977
978 ImGui::Text("Color picker:");
979 static bool alpha = true;
980 static bool alpha_bar = true;
981 static bool side_preview = true;
982 static bool ref_color = false;
983 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
984 static int inputs_mode = 2;
985 static int picker_mode = 0;
986 ImGui::Checkbox("With Alpha", &alpha);
987 ImGui::Checkbox("With Alpha Bar", &alpha_bar);
988 ImGui::Checkbox("With Side Preview", &side_preview);
989 if (side_preview)
990 {
991 ImGui::SameLine();
992 ImGui::Checkbox("With Ref Color", &ref_color);
993 if (ref_color)
994 {
995 ImGui::SameLine();
996 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
997 }
998 }
999 ImGui::Combo("Inputs Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0");
1000 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
1001 ImGui::SameLine();
1002 ShowHelpMarker("User can right-click the picker to change mode.");
1003 ImGuiColorEditFlags flags = misc_flags;
1004 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
1005 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
1006 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
1007 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
1008 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
1009 if (inputs_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;
1010 if (inputs_mode == 2) flags |= ImGuiColorEditFlags_RGB;
1011 if (inputs_mode == 3) flags |= ImGuiColorEditFlags_HSV;
1012 if (inputs_mode == 4) flags |= ImGuiColorEditFlags_HEX;
1013 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
1014
1015 ImGui::Text("Programmatically set defaults/options:");
1016 ImGui::SameLine();
1017 ShowHelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible.");
1018 if (ImGui::Button("Uint8 + HSV"))
1019 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_HSV);
1020 ImGui::SameLine();
1021 if (ImGui::Button("Float + HDR"))
1022 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_RGB);
1023
1024 ImGui::TreePop();
1025 }
1026
1027 if (ImGui::TreeNode("Range Widgets"))
1028 {
1029 static float begin = 10, end = 90;
1030 static int begin_i = 100, end_i = 1000;
1031 ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%");
1032 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %.0f units", "Max: %.0f units");
1033 ImGui::TreePop();
1034 }
1035
1036 if (ImGui::TreeNode("Multi-component Widgets"))
1037 {
1038 static float vec4f[4] = {0.10f, 0.20f, 0.30f, 0.44f};
1039 static int vec4i[4] = {1, 5, 100, 255};
1040
1041 ImGui::InputFloat2("input float2", vec4f);
1042 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
1043 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
1044 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
1045 ImGui::InputInt2("input int2", vec4i);
1046 ImGui::SliderInt2("slider int2", vec4i, 0, 255);
1047 ImGui::Spacing();
1048
1049 ImGui::InputFloat3("input float3", vec4f);
1050 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
1051 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
1052 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
1053 ImGui::InputInt3("input int3", vec4i);
1054 ImGui::SliderInt3("slider int3", vec4i, 0, 255);
1055 ImGui::Spacing();
1056
1057 ImGui::InputFloat4("input float4", vec4f);
1058 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
1059 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
1060 ImGui::InputInt4("input int4", vec4i);
1061 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
1062 ImGui::SliderInt4("slider int4", vec4i, 0, 255);
1063
1064 ImGui::TreePop();
1065 }
1066
1067 if (ImGui::TreeNode("Vertical Sliders"))
1068 {
1069 const float spacing = 4;
1070 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
1071
1072 static int int_value = 0;
1073 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
1074 ImGui::SameLine();
1075
1076 static float values[7] = {0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f};
1077 ImGui::PushID("set1");
1078 for (int i = 0; i < 7; i++)
1079 {
1080 if (i > 0) ImGui::SameLine();
1081 ImGui::PushID(i);
1082 ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f));
1083 ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f));
1084 ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f));
1085 ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f));
1086 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
1087 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
1088 ImGui::SetTooltip("%.3f", values[i]);
1089 ImGui::PopStyleColor(4);
1090 ImGui::PopID();
1091 }
1092 ImGui::PopID();
1093
1094 ImGui::SameLine();
1095 ImGui::PushID("set2");
1096 static float values2[4] = {0.20f, 0.80f, 0.40f, 0.25f};
1097 const int rows = 3;
1098 const ImVec2 small_slider_size(18, (160.0f - (rows - 1) * spacing) / rows);
1099 for (int nx = 0; nx < 4; nx++)
1100 {
1101 if (nx > 0) ImGui::SameLine();
1102 ImGui::BeginGroup();
1103 for (int ny = 0; ny < rows; ny++)
1104 {
1105 ImGui::PushID(nx * rows + ny);
1106 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
1107 if (ImGui::IsItemActive() || ImGui::IsItemHovered())
1108 ImGui::SetTooltip("%.3f", values2[nx]);
1109 ImGui::PopID();
1110 }
1111 ImGui::EndGroup();
1112 }
1113 ImGui::PopID();
1114
1115 ImGui::SameLine();
1116 ImGui::PushID("set3");
1117 for (int i = 0; i < 4; i++)
1118 {
1119 if (i > 0) ImGui::SameLine();
1120 ImGui::PushID(i);
1121 ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
1122 ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec");
1123 ImGui::PopStyleVar();
1124 ImGui::PopID();
1125 }
1126 ImGui::PopID();
1127 ImGui::PopStyleVar();
1128 ImGui::TreePop();
1129 }
1130 }
1131
1132 if (ImGui::CollapsingHeader("Layout"))
1133 {
1134 if (ImGui::TreeNode("Child regions"))
1135 {
1136 static bool disable_mouse_wheel = false;
1137 static bool disable_menu = false;
1138 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
1139 ImGui::Checkbox("Disable Menu", &disable_menu);
1140
1141 static int line = 50;
1142 bool goto_line = ImGui::Button("Goto");
1143 ImGui::SameLine();
1144 ImGui::PushItemWidth(100);
1145 goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue);
1146 ImGui::PopItemWidth();
1147
1148 // Child 1: no border, enable horizontal scrollbar
1149 {
1150 ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 300), false, ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0));
1151 for (int i = 0; i < 100; i++)
1152 {
1153 ImGui::Text("%04d: scrollable region", i);
1154 if (goto_line && line == i)
1155 ImGui::SetScrollHere();
1156 }
1157 if (goto_line && line >= 100)
1158 ImGui::SetScrollHere();
1159 ImGui::EndChild();
1160 }
1161
1162 ImGui::SameLine();
1163
1164 // Child 2: rounded border
1165 {
1166 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
1167 ImGui::BeginChild("Child2", ImVec2(0, 300), true, (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar));
1168 if (!disable_menu && ImGui::BeginMenuBar())
1169 {
1170 if (ImGui::BeginMenu("Menu"))
1171 {
1172 ShowExampleMenuFile();
1173 ImGui::EndMenu();
1174 }
1175 ImGui::EndMenuBar();
1176 }
1177 ImGui::Columns(2);
1178 for (int i = 0; i < 100; i++)
1179 {
1180 if (i == 50)
1181 ImGui::NextColumn();
1182 char buf[32];
1183 sprintf(buf, "%08x", i * 5731);
1184 ImGui::Button(buf, ImVec2(-1.0f, 0.0f));
1185 }
1186 ImGui::EndChild();
1187 ImGui::PopStyleVar();
1188 }
1189
1190 ImGui::TreePop();
1191 }
1192
1193 if (ImGui::TreeNode("Widgets Width"))
1194 {
1195 static float f = 0.0f;
1196 ImGui::Text("PushItemWidth(100)");
1197 ImGui::SameLine();
1198 ShowHelpMarker("Fixed width.");
1199 ImGui::PushItemWidth(100);
1200 ImGui::DragFloat("float##1", &f);
1201 ImGui::PopItemWidth();
1202
1203 ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f)");
1204 ImGui::SameLine();
1205 ShowHelpMarker("Half of window width.");
1206 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
1207 ImGui::DragFloat("float##2", &f);
1208 ImGui::PopItemWidth();
1209
1210 ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)");
1211 ImGui::SameLine();
1212 ShowHelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
1213 ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f);
1214 ImGui::DragFloat("float##3", &f);
1215 ImGui::PopItemWidth();
1216
1217 ImGui::Text("PushItemWidth(-100)");
1218 ImGui::SameLine();
1219 ShowHelpMarker("Align to right edge minus 100");
1220 ImGui::PushItemWidth(-100);
1221 ImGui::DragFloat("float##4", &f);
1222 ImGui::PopItemWidth();
1223
1224 ImGui::Text("PushItemWidth(-1)");
1225 ImGui::SameLine();
1226 ShowHelpMarker("Align to right edge");
1227 ImGui::PushItemWidth(-1);
1228 ImGui::DragFloat("float##5", &f);
1229 ImGui::PopItemWidth();
1230
1231 ImGui::TreePop();
1232 }
1233
1234 if (ImGui::TreeNode("Basic Horizontal Layout"))
1235 {
1236 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
1237
1238 // Text
1239 ImGui::Text("Two items: Hello");
1240 ImGui::SameLine();
1241 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
1242
1243 // Adjust spacing
1244 ImGui::Text("More spacing: Hello");
1245 ImGui::SameLine(0, 20);
1246 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
1247
1248 // Button
1249 ImGui::AlignTextToFramePadding();
1250 ImGui::Text("Normal buttons");
1251 ImGui::SameLine();
1252 ImGui::Button("Banana");
1253 ImGui::SameLine();
1254 ImGui::Button("Apple");
1255 ImGui::SameLine();
1256 ImGui::Button("Corniflower");
1257
1258 // Button
1259 ImGui::Text("Small buttons");
1260 ImGui::SameLine();
1261 ImGui::SmallButton("Like this one");
1262 ImGui::SameLine();
1263 ImGui::Text("can fit within a text block.");
1264
1265 // Aligned to arbitrary position. Easy/cheap column.
1266 ImGui::Text("Aligned");
1267 ImGui::SameLine(150);
1268 ImGui::Text("x=150");
1269 ImGui::SameLine(300);
1270 ImGui::Text("x=300");
1271 ImGui::Text("Aligned");
1272 ImGui::SameLine(150);
1273 ImGui::SmallButton("x=150");
1274 ImGui::SameLine(300);
1275 ImGui::SmallButton("x=300");
1276
1277 // Checkbox
1278 static bool c1 = false, c2 = false, c3 = false, c4 = false;
1279 ImGui::Checkbox("My", &c1);
1280 ImGui::SameLine();
1281 ImGui::Checkbox("Tailor", &c2);
1282 ImGui::SameLine();
1283 ImGui::Checkbox("Is", &c3);
1284 ImGui::SameLine();
1285 ImGui::Checkbox("Rich", &c4);
1286
1287 // Various
1288 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
1289 ImGui::PushItemWidth(80);
1290 const char* items[] = {"AAAA", "BBBB", "CCCC", "DDDD"};
1291 static int item = -1;
1292 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items));
1293 ImGui::SameLine();
1294 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f);
1295 ImGui::SameLine();
1296 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f);
1297 ImGui::SameLine();
1298 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
1299 ImGui::PopItemWidth();
1300
1301 ImGui::PushItemWidth(80);
1302 ImGui::Text("Lists:");
1303 static int selection[4] = {0, 1, 2, 3};
1304 for (int i = 0; i < 4; i++)
1305 {
1306 if (i > 0) ImGui::SameLine();
1307 ImGui::PushID(i);
1308 ImGui::ListBox("", &selection[i], items, IM_ARRAYSIZE(items));
1309 ImGui::PopID();
1310 //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i);
1311 }
1312 ImGui::PopItemWidth();
1313
1314 // Dummy
1315 ImVec2 sz(30, 30);
1316 ImGui::Button("A", sz);
1317 ImGui::SameLine();
1318 ImGui::Dummy(sz);
1319 ImGui::SameLine();
1320 ImGui::Button("B", sz);
1321
1322 ImGui::TreePop();
1323 }
1324
1325 if (ImGui::TreeNode("Groups"))
1326 {
1327 ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)");
1328 ImGui::BeginGroup();
1329 {
1330 ImGui::BeginGroup();
1331 ImGui::Button("AAA");
1332 ImGui::SameLine();
1333 ImGui::Button("BBB");
1334 ImGui::SameLine();
1335 ImGui::BeginGroup();
1336 ImGui::Button("CCC");
1337 ImGui::Button("DDD");
1338 ImGui::EndGroup();
1339 ImGui::SameLine();
1340 ImGui::Button("EEE");
1341 ImGui::EndGroup();
1342 if (ImGui::IsItemHovered())
1343 ImGui::SetTooltip("First group hovered");
1344 }
1345 // Capture the group size and create widgets using the same size
1346 ImVec2 size = ImGui::GetItemRectSize();
1347 const float values[5] = {0.5f, 0.20f, 0.80f, 0.60f, 0.25f};
1348 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
1349
1350 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
1351 ImGui::SameLine();
1352 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
1353 ImGui::EndGroup();
1354 ImGui::SameLine();
1355
1356 ImGui::Button("LEVERAGE\nBUZZWORD", size);
1357 ImGui::SameLine();
1358
1359 ImGui::ListBoxHeader("List", size);
1360 ImGui::Selectable("Selected", true);
1361 ImGui::Selectable("Not Selected", false);
1362 ImGui::ListBoxFooter();
1363
1364 ImGui::TreePop();
1365 }
1366
1367 if (ImGui::TreeNode("Text Baseline Alignment"))
1368 {
1369 ImGui::TextWrapped("(This is testing the vertical alignment that occurs on text to keep it at the same baseline as widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets)");
1370
1371 ImGui::Text("One\nTwo\nThree");
1372 ImGui::SameLine();
1373 ImGui::Text("Hello\nWorld");
1374 ImGui::SameLine();
1375 ImGui::Text("Banana");
1376
1377 ImGui::Text("Banana");
1378 ImGui::SameLine();
1379 ImGui::Text("Hello\nWorld");
1380 ImGui::SameLine();
1381 ImGui::Text("One\nTwo\nThree");
1382
1383 ImGui::Button("HOP##1");
1384 ImGui::SameLine();
1385 ImGui::Text("Banana");
1386 ImGui::SameLine();
1387 ImGui::Text("Hello\nWorld");
1388 ImGui::SameLine();
1389 ImGui::Text("Banana");
1390
1391 ImGui::Button("HOP##2");
1392 ImGui::SameLine();
1393 ImGui::Text("Hello\nWorld");
1394 ImGui::SameLine();
1395 ImGui::Text("Banana");
1396
1397 ImGui::Button("TEST##1");
1398 ImGui::SameLine();
1399 ImGui::Text("TEST");
1400 ImGui::SameLine();
1401 ImGui::SmallButton("TEST##2");
1402
1403 ImGui::AlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets.
1404 ImGui::Text("Text aligned to Widget");
1405 ImGui::SameLine();
1406 ImGui::Button("Widget##1");
1407 ImGui::SameLine();
1408 ImGui::Text("Widget");
1409 ImGui::SameLine();
1410 ImGui::SmallButton("Widget##2");
1411 ImGui::SameLine();
1412 ImGui::Button("Widget##3");
1413
1414 // Tree
1415 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
1416 ImGui::Button("Button##1");
1417 ImGui::SameLine(0.0f, spacing);
1418 if (ImGui::TreeNode("Node##1"))
1419 {
1420 for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i);
1421 ImGui::TreePop();
1422 } // Dummy tree data
1423
1424 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).
1425 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.
1426 ImGui::SameLine(0.0f, spacing);
1427 ImGui::Button("Button##2");
1428 if (node_open)
1429 {
1430 for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i);
1431 ImGui::TreePop();
1432 } // Dummy tree data
1433
1434 // Bullet
1435 ImGui::Button("Button##3");
1436 ImGui::SameLine(0.0f, spacing);
1437 ImGui::BulletText("Bullet text");
1438
1439 ImGui::AlignTextToFramePadding();
1440 ImGui::BulletText("Node");
1441 ImGui::SameLine(0.0f, spacing);
1442 ImGui::Button("Button##4");
1443
1444 ImGui::TreePop();
1445 }
1446
1447 if (ImGui::TreeNode("Scrolling"))
1448 {
1449 ImGui::TextWrapped("(Use SetScrollHere() or SetScrollFromPosY() to scroll to a given position.)");
1450 static bool track = true;
1451 static int track_line = 50, scroll_to_px = 200;
1452 ImGui::Checkbox("Track", &track);
1453 ImGui::PushItemWidth(100);
1454 ImGui::SameLine(130);
1455 track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %.0f");
1456 bool scroll_to = ImGui::Button("Scroll To Pos");
1457 ImGui::SameLine(130);
1458 scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %.0f px");
1459 ImGui::PopItemWidth();
1460 if (scroll_to) track = false;
1461
1462 for (int i = 0; i < 5; i++)
1463 {
1464 if (i > 0) ImGui::SameLine();
1465 ImGui::BeginGroup();
1466 ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom");
1467 ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true);
1468 if (scroll_to)
1469 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f);
1470 for (int line = 0; line < 100; line++)
1471 {
1472 if (track && line == track_line)
1473 {
1474 ImGui::TextColored(ImColor(255, 255, 0), "Line %d", line);
1475 ImGui::SetScrollHere(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
1476 }
1477 else
1478 {
1479 ImGui::Text("Line %d", line);
1480 }
1481 }
1482 float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY();
1483 ImGui::EndChild();
1484 ImGui::Text("%.0f/%0.f", scroll_y, scroll_max_y);
1485 ImGui::EndGroup();
1486 }
1487 ImGui::TreePop();
1488 }
1489
1490 if (ImGui::TreeNode("Horizontal Scrolling"))
1491 {
1492 ImGui::Bullet();
1493 ImGui::TextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.");
1494 ImGui::Bullet();
1495 ImGui::TextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin().");
1496 static int lines = 7;
1497 ImGui::SliderInt("Lines", &lines, 1, 15);
1498 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
1499 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
1500 ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar);
1501 for (int line = 0; line < lines; line++)
1502 {
1503 // 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
1504 // 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)
1505 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
1506 for (int n = 0; n < num_buttons; n++)
1507 {
1508 if (n > 0) ImGui::SameLine();
1509 ImGui::PushID(n + line * 1000);
1510 char num_buf[16];
1511 sprintf(num_buf, "%d", n);
1512 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
1513 float hue = n * 0.05f;
1514 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
1515 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
1516 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
1517 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
1518 ImGui::PopStyleColor(3);
1519 ImGui::PopID();
1520 }
1521 }
1522 float scroll_x = ImGui::GetScrollX(), scroll_max_x = ImGui::GetScrollMaxX();
1523 ImGui::EndChild();
1524 ImGui::PopStyleVar(2);
1525 float scroll_x_delta = 0.0f;
1526 ImGui::SmallButton("<<");
1527 if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
1528 ImGui::SameLine();
1529 ImGui::Text("Scroll from code");
1530 ImGui::SameLine();
1531 ImGui::SmallButton(">>");
1532 if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
1533 ImGui::SameLine();
1534 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
1535 if (scroll_x_delta != 0.0f)
1536 {
1537 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)
1538 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
1539 ImGui::End();
1540 }
1541 ImGui::TreePop();
1542 }
1543
1544 if (ImGui::TreeNode("Clipping"))
1545 {
1546 static ImVec2 size(100, 100), offset(50, 20);
1547 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.");
1548 ImGui::DragFloat2("size", (float*)&size, 0.5f, 0.0f, 200.0f, "%.0f");
1549 ImGui::TextWrapped("(Click and drag)");
1550 ImVec2 pos = ImGui::GetCursorScreenPos();
1551 ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y);
1552 ImGui::InvisibleButton("##dummy", size);
1553 if (ImGui::IsItemActive() && ImGui::IsMouseDragging())
1554 {
1555 offset.x += ImGui::GetIO().MouseDelta.x;
1556 offset.y += ImGui::GetIO().MouseDelta.y;
1557 }
1558 ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255));
1559 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);
1560 ImGui::TreePop();
1561 }
1562 }
1563
1564 if (ImGui::CollapsingHeader("Popups & Modal windows"))
1565 {
1566 if (ImGui::TreeNode("Popups"))
1567 {
1568 ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it.");
1569
1570 static int selected_fish = -1;
1571 const char* names[] = {"Bream", "Haddock", "Mackerel", "Pollock", "Tilefish"};
1572 static bool toggles[] = {true, false, false, false, false};
1573
1574 // Simple selection popup
1575 // (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)
1576 if (ImGui::Button("Select.."))
1577 ImGui::OpenPopup("select");
1578 ImGui::SameLine();
1579 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
1580 if (ImGui::BeginPopup("select"))
1581 {
1582 ImGui::Text("Aquarium");
1583 ImGui::Separator();
1584 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
1585 if (ImGui::Selectable(names[i]))
1586 selected_fish = i;
1587 ImGui::EndPopup();
1588 }
1589
1590 // Showing a menu with toggles
1591 if (ImGui::Button("Toggle.."))
1592 ImGui::OpenPopup("toggle");
1593 if (ImGui::BeginPopup("toggle"))
1594 {
1595 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
1596 ImGui::MenuItem(names[i], "", &toggles[i]);
1597 if (ImGui::BeginMenu("Sub-menu"))
1598 {
1599 ImGui::MenuItem("Click me");
1600 ImGui::EndMenu();
1601 }
1602
1603 ImGui::Separator();
1604 ImGui::Text("Tooltip here");
1605 if (ImGui::IsItemHovered())
1606 ImGui::SetTooltip("I am a tooltip over a popup");
1607
1608 if (ImGui::Button("Stacked Popup"))
1609 ImGui::OpenPopup("another popup");
1610 if (ImGui::BeginPopup("another popup"))
1611 {
1612 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
1613 ImGui::MenuItem(names[i], "", &toggles[i]);
1614 if (ImGui::BeginMenu("Sub-menu"))
1615 {
1616 ImGui::MenuItem("Click me");
1617 ImGui::EndMenu();
1618 }
1619 ImGui::EndPopup();
1620 }
1621 ImGui::EndPopup();
1622 }
1623
1624 if (ImGui::Button("Popup Menu.."))
1625 ImGui::OpenPopup("FilePopup");
1626 if (ImGui::BeginPopup("FilePopup"))
1627 {
1628 ShowExampleMenuFile();
1629 ImGui::EndPopup();
1630 }
1631
1632 ImGui::TreePop();
1633 }
1634
1635 if (ImGui::TreeNode("Context menus"))
1636 {
1637 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
1638 // if (IsItemHovered() && IsMouseClicked(0))
1639 // OpenPopup(id);
1640 // return BeginPopup(id);
1641 // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation.
1642 static float value = 0.5f;
1643 ImGui::Text("Value = %.3f (<-- right-click here)", value);
1644 if (ImGui::BeginPopupContextItem("item context menu"))
1645 {
1646 if (ImGui::Selectable("Set to zero")) value = 0.0f;
1647 if (ImGui::Selectable("Set to PI")) value = 3.1415f;
1648 ImGui::PushItemWidth(-1);
1649 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
1650 ImGui::PopItemWidth();
1651 ImGui::EndPopup();
1652 }
1653
1654 static char name[32] = "Label1";
1655 char buf[64];
1656 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
1657 ImGui::Button(buf);
1658 if (ImGui::BeginPopupContextItem()) // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem().
1659 {
1660 ImGui::Text("Edit name:");
1661 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
1662 if (ImGui::Button("Close"))
1663 ImGui::CloseCurrentPopup();
1664 ImGui::EndPopup();
1665 }
1666 ImGui::SameLine();
1667 ImGui::Text("(<-- right-click here)");
1668
1669 ImGui::TreePop();
1670 }
1671
1672 if (ImGui::TreeNode("Modals"))
1673 {
1674 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window.");
1675
1676 if (ImGui::Button("Delete.."))
1677 ImGui::OpenPopup("Delete?");
1678 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
1679 {
1680 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
1681 ImGui::Separator();
1682
1683 //static int dummy_i = 0;
1684 //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0");
1685
1686 static bool dont_ask_me_next_time = false;
1687 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
1688 ImGui::Checkbox("Don't ask me next time", &dont_ask_me_next_time);
1689 ImGui::PopStyleVar();
1690
1691 if (ImGui::Button("OK", ImVec2(120, 0)))
1692 {
1693 ImGui::CloseCurrentPopup();
1694 }
1695 ImGui::SetItemDefaultFocus();
1696 ImGui::SameLine();
1697 if (ImGui::Button("Cancel", ImVec2(120, 0)))
1698 {
1699 ImGui::CloseCurrentPopup();
1700 }
1701 ImGui::EndPopup();
1702 }
1703
1704 if (ImGui::Button("Stacked modals.."))
1705 ImGui::OpenPopup("Stacked 1");
1706 if (ImGui::BeginPopupModal("Stacked 1"))
1707 {
1708 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDarkening] for darkening.");
1709 static int item = 1;
1710 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1711 static float color[4] = {0.4f, 0.7f, 0.0f, 0.5f};
1712 ImGui::ColorEdit4("color", color); // This is to test behavior of stacked regular popups over a modal
1713
1714 if (ImGui::Button("Add another modal.."))
1715 ImGui::OpenPopup("Stacked 2");
1716 if (ImGui::BeginPopupModal("Stacked 2"))
1717 {
1718 ImGui::Text("Hello from Stacked The Second!");
1719 if (ImGui::Button("Close"))
1720 ImGui::CloseCurrentPopup();
1721 ImGui::EndPopup();
1722 }
1723
1724 if (ImGui::Button("Close"))
1725 ImGui::CloseCurrentPopup();
1726 ImGui::EndPopup();
1727 }
1728
1729 ImGui::TreePop();
1730 }
1731
1732 if (ImGui::TreeNode("Menus inside a regular window"))
1733 {
1734 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
1735 ImGui::Separator();
1736 // 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.
1737 // 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
1738 // 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.
1739 ImGui::PushID("foo");
1740 ImGui::MenuItem("Menu item", "CTRL+M");
1741 if (ImGui::BeginMenu("Menu inside a regular window"))
1742 {
1743 ShowExampleMenuFile();
1744 ImGui::EndMenu();
1745 }
1746 ImGui::PopID();
1747 ImGui::Separator();
1748 ImGui::TreePop();
1749 }
1750 }
1751
1752 if (ImGui::CollapsingHeader("Columns"))
1753 {
1754 ImGui::PushID("Columns");
1755
1756 // Basic columns
1757 if (ImGui::TreeNode("Basic"))
1758 {
1759 ImGui::Text("Without border:");
1760 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border
1761 ImGui::Separator();
1762 for (int n = 0; n < 14; n++)
1763 {
1764 char label[32];
1765 sprintf(label, "Item %d", n);
1766 if (ImGui::Selectable(label))
1767 {
1768 }
1769 //if (ImGui::Button(label, ImVec2(-1,0))) {}
1770 ImGui::NextColumn();
1771 }
1772 ImGui::Columns(1);
1773 ImGui::Separator();
1774
1775 ImGui::Text("With border:");
1776 ImGui::Columns(4, "mycolumns"); // 4-ways, with border
1777 ImGui::Separator();
1778 ImGui::Text("ID");
1779 ImGui::NextColumn();
1780 ImGui::Text("Name");
1781 ImGui::NextColumn();
1782 ImGui::Text("Path");
1783 ImGui::NextColumn();
1784 ImGui::Text("Hovered");
1785 ImGui::NextColumn();
1786 ImGui::Separator();
1787 const char* names[3] = {"One", "Two", "Three"};
1788 const char* paths[3] = {"/path/one", "/path/two", "/path/three"};
1789 static int selected = -1;
1790 for (int i = 0; i < 3; i++)
1791 {
1792 char label[32];
1793 sprintf(label, "%04d", i);
1794 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
1795 selected = i;
1796 bool hovered = ImGui::IsItemHovered();
1797 ImGui::NextColumn();
1798 ImGui::Text(names[i]);
1799 ImGui::NextColumn();
1800 ImGui::Text(paths[i]);
1801 ImGui::NextColumn();
1802 ImGui::Text("%d", hovered);
1803 ImGui::NextColumn();
1804 }
1805 ImGui::Columns(1);
1806 ImGui::Separator();
1807 ImGui::TreePop();
1808 }
1809
1810 // Create multiple items in a same cell before switching to next column
1811 if (ImGui::TreeNode("Mixed items"))
1812 {
1813 ImGui::Columns(3, "mixed");
1814 ImGui::Separator();
1815
1816 ImGui::Text("Hello");
1817 ImGui::Button("Banana");
1818 ImGui::NextColumn();
1819
1820 ImGui::Text("ImGui");
1821 ImGui::Button("Apple");
1822 static float foo = 1.0f;
1823 ImGui::InputFloat("red", &foo, 0.05f, 0, 3);
1824 ImGui::Text("An extra line here.");
1825 ImGui::NextColumn();
1826
1827 ImGui::Text("Sailor");
1828 ImGui::Button("Corniflower");
1829 static float bar = 1.0f;
1830 ImGui::InputFloat("blue", &bar, 0.05f, 0, 3);
1831 ImGui::NextColumn();
1832
1833 if (ImGui::CollapsingHeader("Category A"))
1834 {
1835 ImGui::Text("Blah blah blah");
1836 }
1837 ImGui::NextColumn();
1838 if (ImGui::CollapsingHeader("Category B"))
1839 {
1840 ImGui::Text("Blah blah blah");
1841 }
1842 ImGui::NextColumn();
1843 if (ImGui::CollapsingHeader("Category C"))
1844 {
1845 ImGui::Text("Blah blah blah");
1846 }
1847 ImGui::NextColumn();
1848 ImGui::Columns(1);
1849 ImGui::Separator();
1850 ImGui::TreePop();
1851 }
1852
1853 // Word wrapping
1854 if (ImGui::TreeNode("Word-wrapping"))
1855 {
1856 ImGui::Columns(2, "word-wrapping");
1857 ImGui::Separator();
1858 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
1859 ImGui::TextWrapped("Hello Left");
1860 ImGui::NextColumn();
1861 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
1862 ImGui::TextWrapped("Hello Right");
1863 ImGui::Columns(1);
1864 ImGui::Separator();
1865 ImGui::TreePop();
1866 }
1867
1868 if (ImGui::TreeNode("Borders"))
1869 {
1870 // NB: Future columns API should allow automatic horizontal borders.
1871 static bool h_borders = true;
1872 static bool v_borders = true;
1873 ImGui::Checkbox("horizontal", &h_borders);
1874 ImGui::SameLine();
1875 ImGui::Checkbox("vertical", &v_borders);
1876 ImGui::Columns(4, NULL, v_borders);
1877 for (int i = 0; i < 4 * 3; i++)
1878 {
1879 if (h_borders && ImGui::GetColumnIndex() == 0)
1880 ImGui::Separator();
1881 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
1882 ImGui::Text("Width %.2f\nOffset %.2f", ImGui::GetColumnWidth(), ImGui::GetColumnOffset());
1883 ImGui::NextColumn();
1884 }
1885 ImGui::Columns(1);
1886 if (h_borders)
1887 ImGui::Separator();
1888 ImGui::TreePop();
1889 }
1890
1891 // Scrolling columns
1892 /*
1893 if (ImGui::TreeNode("Vertical Scrolling"))
1894 {
1895 ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
1896 ImGui::Columns(3);
1897 ImGui::Text("ID"); ImGui::NextColumn();
1898 ImGui::Text("Name"); ImGui::NextColumn();
1899 ImGui::Text("Path"); ImGui::NextColumn();
1900 ImGui::Columns(1);
1901 ImGui::Separator();
1902 ImGui::EndChild();
1903 ImGui::BeginChild("##scrollingregion", ImVec2(0, 60));
1904 ImGui::Columns(3);
1905 for (int i = 0; i < 10; i++)
1906 {
1907 ImGui::Text("%04d", i); ImGui::NextColumn();
1908 ImGui::Text("Foobar"); ImGui::NextColumn();
1909 ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn();
1910 }
1911 ImGui::Columns(1);
1912 ImGui::EndChild();
1913 ImGui::TreePop();
1914 }
1915 */
1916
1917 if (ImGui::TreeNode("Horizontal Scrolling"))
1918 {
1919 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
1920 ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar);
1921 ImGui::Columns(10);
1922 int ITEMS_COUNT = 2000;
1923 ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list
1924 while (clipper.Step())
1925 {
1926 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
1927 for (int j = 0; j < 10; j++)
1928 {
1929 ImGui::Text("Line %d Column %d...", i, j);
1930 ImGui::NextColumn();
1931 }
1932 }
1933 ImGui::Columns(1);
1934 ImGui::EndChild();
1935 ImGui::TreePop();
1936 }
1937
1938 bool node_open = ImGui::TreeNode("Tree within single cell");
1939 ImGui::SameLine();
1940 ShowHelpMarker("NB: Tree node must be poped before ending the cell. There's no storage of state per-cell.");
1941 if (node_open)
1942 {
1943 ImGui::Columns(2, "tree items");
1944 ImGui::Separator();
1945 if (ImGui::TreeNode("Hello"))
1946 {
1947 ImGui::BulletText("Sailor");
1948 ImGui::TreePop();
1949 }
1950 ImGui::NextColumn();
1951 if (ImGui::TreeNode("Bonjour"))
1952 {
1953 ImGui::BulletText("Marin");
1954 ImGui::TreePop();
1955 }
1956 ImGui::NextColumn();
1957 ImGui::Columns(1);
1958 ImGui::Separator();
1959 ImGui::TreePop();
1960 }
1961 ImGui::PopID();
1962 }
1963
1964 if (ImGui::CollapsingHeader("Filtering"))
1965 {
1966 static ImGuiTextFilter filter;
1967 ImGui::Text(
1968 "Filter usage:\n"
1969 " \"\" display all lines\n"
1970 " \"xxx\" display lines containing \"xxx\"\n"
1971 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
1972 " \"-xxx\" hide lines containing \"xxx\"");
1973 filter.Draw();
1974 const char* lines[] = {"aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world"};
1975 for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
1976 if (filter.PassFilter(lines[i]))
1977 ImGui::BulletText("%s", lines[i]);
1978 }
1979
1980 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus"))
1981 {
1982 ImGuiIO& io = ImGui::GetIO();
1983
1984 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
1985 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
1986 ImGui::Text("WantTextInput: %d", io.WantTextInput);
1987 ImGui::Text("WantMoveMouse: %d", io.WantMoveMouse);
1988 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible);
1989
1990 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
1991 ImGui::SameLine();
1992 ShowHelpMarker("Request ImGui to render a mouse cursor for you in software. 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).");
1993 ImGui::CheckboxFlags("io.NavFlags: EnableGamepad", (unsigned int*)&io.NavFlags, ImGuiNavFlags_EnableGamepad);
1994 ImGui::CheckboxFlags("io.NavFlags: EnableKeyboard", (unsigned int*)&io.NavFlags, ImGuiNavFlags_EnableKeyboard);
1995 ImGui::CheckboxFlags("io.NavFlags: MoveMouse", (unsigned int*)&io.NavFlags, ImGuiNavFlags_MoveMouse);
1996 ImGui::SameLine();
1997 ShowHelpMarker("Request ImGui to move your move cursor when using gamepad/keyboard navigation. NewFrame() will change io.MousePos and set the io.WantMoveMouse flag, your backend will need to apply the new mouse position.");
1998
1999 if (ImGui::TreeNode("Keyboard, Mouse & Navigation State"))
2000 {
2001 if (ImGui::IsMousePosValid())
2002 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
2003 else
2004 ImGui::Text("Mouse pos: <INVALID>");
2005 ImGui::Text("Mouse down:");
2006 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
2007 if (io.MouseDownDuration[i] >= 0.0f)
2008 {
2009 ImGui::SameLine();
2010 ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]);
2011 }
2012 ImGui::Text("Mouse clicked:");
2013 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
2014 if (ImGui::IsMouseClicked(i))
2015 {
2016 ImGui::SameLine();
2017 ImGui::Text("b%d", i);
2018 }
2019 ImGui::Text("Mouse dbl-clicked:");
2020 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
2021 if (ImGui::IsMouseDoubleClicked(i))
2022 {
2023 ImGui::SameLine();
2024 ImGui::Text("b%d", i);
2025 }
2026 ImGui::Text("Mouse released:");
2027 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
2028 if (ImGui::IsMouseReleased(i))
2029 {
2030 ImGui::SameLine();
2031 ImGui::Text("b%d", i);
2032 }
2033 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
2034
2035 ImGui::Text("Keys down:");
2036 for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++)
2037 if (io.KeysDownDuration[i] >= 0.0f)
2038 {
2039 ImGui::SameLine();
2040 ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]);
2041 }
2042 ImGui::Text("Keys pressed:");
2043 for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++)
2044 if (ImGui::IsKeyPressed(i))
2045 {
2046 ImGui::SameLine();
2047 ImGui::Text("%d", i);
2048 }
2049 ImGui::Text("Keys release:");
2050 for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++)
2051 if (ImGui::IsKeyReleased(i))
2052 {
2053 ImGui::SameLine();
2054 ImGui::Text("%d", i);
2055 }
2056 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
2057
2058 ImGui::Text("NavInputs down:");
2059 for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++)
2060 if (io.NavInputs[i] > 0.0f)
2061 {
2062 ImGui::SameLine();
2063 ImGui::Text("[%d] %.2f", i, io.NavInputs[i]);
2064 }
2065 ImGui::Text("NavInputs pressed:");
2066 for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++)
2067 if (io.NavInputsDownDuration[i] == 0.0f)
2068 {
2069 ImGui::SameLine();
2070 ImGui::Text("[%d]", i);
2071 }
2072 ImGui::Text("NavInputs duration:");
2073 for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++)
2074 if (io.NavInputsDownDuration[i] >= 0.0f)
2075 {
2076 ImGui::SameLine();
2077 ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]);
2078 }
2079
2080 ImGui::Button("Hovering me sets the\nkeyboard capture flag");
2081 if (ImGui::IsItemHovered())
2082 ImGui::CaptureKeyboardFromApp(true);
2083 ImGui::SameLine();
2084 ImGui::Button("Holding me clears the\nthe keyboard capture flag");
2085 if (ImGui::IsItemActive())
2086 ImGui::CaptureKeyboardFromApp(false);
2087
2088 ImGui::TreePop();
2089 }
2090
2091 if (ImGui::TreeNode("Tabbing"))
2092 {
2093 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
2094 static char buf[32] = "dummy";
2095 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
2096 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
2097 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
2098 ImGui::PushAllowKeyboardFocus(false);
2099 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
2100 //ImGui::SameLine(); ShowHelperMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets.");
2101 ImGui::PopAllowKeyboardFocus();
2102 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
2103 ImGui::TreePop();
2104 }
2105
2106 if (ImGui::TreeNode("Focus from code"))
2107 {
2108 bool focus_1 = ImGui::Button("Focus on 1");
2109 ImGui::SameLine();
2110 bool focus_2 = ImGui::Button("Focus on 2");
2111 ImGui::SameLine();
2112 bool focus_3 = ImGui::Button("Focus on 3");
2113 int has_focus = 0;
2114 static char buf[128] = "click on a button to set focus";
2115
2116 if (focus_1) ImGui::SetKeyboardFocusHere();
2117 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
2118 if (ImGui::IsItemActive()) has_focus = 1;
2119
2120 if (focus_2) ImGui::SetKeyboardFocusHere();
2121 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
2122 if (ImGui::IsItemActive()) has_focus = 2;
2123
2124 ImGui::PushAllowKeyboardFocus(false);
2125 if (focus_3) ImGui::SetKeyboardFocusHere();
2126 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
2127 if (ImGui::IsItemActive()) has_focus = 3;
2128 ImGui::PopAllowKeyboardFocus();
2129
2130 if (has_focus)
2131 ImGui::Text("Item with focus: %d", has_focus);
2132 else
2133 ImGui::Text("Item with focus: <none>");
2134
2135 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
2136 static float f3[3] = {0.0f, 0.0f, 0.0f};
2137 int focus_ahead = -1;
2138 if (ImGui::Button("Focus on X")) focus_ahead = 0;
2139 ImGui::SameLine();
2140 if (ImGui::Button("Focus on Y")) focus_ahead = 1;
2141 ImGui::SameLine();
2142 if (ImGui::Button("Focus on Z")) focus_ahead = 2;
2143 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
2144 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
2145
2146 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
2147 ImGui::TreePop();
2148 }
2149
2150 if (ImGui::TreeNode("Focused & Hovered Test"))
2151 {
2152 static bool embed_all_inside_a_child_window = false;
2153 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window);
2154 if (embed_all_inside_a_child_window)
2155 ImGui::BeginChild("embeddingchild", ImVec2(0, ImGui::GetFontSize() * 25), true);
2156
2157 // Testing IsWindowFocused() function with its various flags (note that the flags can be combined)
2158 ImGui::BulletText(
2159 "IsWindowFocused() = %d\n"
2160 "IsWindowFocused(_ChildWindows) = %d\n"
2161 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
2162 "IsWindowFocused(_RootWindow) = %d\n"
2163 "IsWindowFocused(_AnyWindow) = %d\n",
2164 ImGui::IsWindowFocused(),
2165 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
2166 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
2167 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
2168 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
2169
2170 // Testing IsWindowHovered() function with its various flags (note that the flags can be combined)
2171 ImGui::BulletText(
2172 "IsWindowHovered() = %d\n"
2173 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
2174 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2175 "IsWindowHovered(_ChildWindows) = %d\n"
2176 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
2177 "IsWindowHovered(_RootWindow) = %d\n"
2178 "IsWindowHovered(_AnyWindow) = %d\n",
2179 ImGui::IsWindowHovered(),
2180 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2181 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2182 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
2183 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
2184 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
2185 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));
2186
2187 // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code)
2188 ImGui::Button("ITEM");
2189 ImGui::BulletText(
2190 "IsItemHovered() = %d\n"
2191 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
2192 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
2193 "IsItemHovered(_AllowWhenOverlapped) = %d\n"
2194 "IsItemhovered(_RectOnly) = %d\n",
2195 ImGui::IsItemHovered(),
2196 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
2197 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
2198 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped),
2199 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly));
2200
2201 ImGui::BeginChild("child", ImVec2(0, 50), true);
2202 ImGui::Text("This is another child window for testing IsWindowHovered() flags.");
2203 ImGui::EndChild();
2204
2205 if (embed_all_inside_a_child_window)
2206 EndChild();
2207
2208 ImGui::TreePop();
2209 }
2210
2211 if (ImGui::TreeNode("Dragging"))
2212 {
2213 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
2214 for (int button = 0; button < 3; button++)
2215 ImGui::Text("IsMouseDragging(%d):\n w/ default threshold: %d,\n w/ zero threshold: %d\n w/ large threshold: %d",
2216 button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f));
2217 ImGui::Button("Drag Me");
2218 if (ImGui::IsItemActive())
2219 {
2220 // Draw a line between the button and the mouse cursor
2221 ImDrawList* draw_list = ImGui::GetWindowDrawList();
2222 draw_list->PushClipRectFullScreen();
2223 draw_list->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f);
2224 draw_list->PopClipRect();
2225
2226 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold)
2227 // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta()
2228 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
2229 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
2230 ImVec2 mouse_delta = io.MouseDelta;
2231 ImGui::SameLine();
2232 ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y);
2233 }
2234 ImGui::TreePop();
2235 }
2236
2237 if (ImGui::TreeNode("Mouse cursors"))
2238 {
2239 const char* mouse_cursors_names[] = {"Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE"};
2240 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_Count_);
2241
2242 ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]);
2243 ImGui::Text("Hover to see mouse cursors:");
2244 ImGui::SameLine();
2245 ShowHelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it.");
2246 for (int i = 0; i < ImGuiMouseCursor_Count_; i++)
2247 {
2248 char label[32];
2249 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
2250 ImGui::Bullet();
2251 ImGui::Selectable(label, false);
2252 if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
2253 ImGui::SetMouseCursor(i);
2254 }
2255 ImGui::TreePop();
2256 }
2257 }
2258
2259 ImGui::End();
2260 }
2261
2262 // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
2263 // 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)2264 bool ImGui::ShowStyleSelector(const char* label)
2265 {
2266 static int style_idx = -1;
2267 if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))
2268 {
2269 switch (style_idx)
2270 {
2271 case 0:
2272 ImGui::StyleColorsClassic();
2273 break;
2274 case 1:
2275 ImGui::StyleColorsDark();
2276 break;
2277 case 2:
2278 ImGui::StyleColorsLight();
2279 break;
2280 }
2281 return true;
2282 }
2283 return false;
2284 }
2285
2286 // Demo helper function to select among loaded fonts.
2287 // Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one.
ShowFontSelector(const char * label)2288 void ImGui::ShowFontSelector(const char* label)
2289 {
2290 ImGuiIO& io = ImGui::GetIO();
2291 ImFont* font_current = ImGui::GetFont();
2292 if (ImGui::BeginCombo(label, font_current->GetDebugName()))
2293 {
2294 for (int n = 0; n < io.Fonts->Fonts.Size; n++)
2295 if (ImGui::Selectable(io.Fonts->Fonts[n]->GetDebugName(), io.Fonts->Fonts[n] == font_current))
2296 io.FontDefault = io.Fonts->Fonts[n];
2297 ImGui::EndCombo();
2298 }
2299 ImGui::SameLine();
2300 ShowHelpMarker(
2301 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
2302 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
2303 "- Read FAQ and documentation in misc/fonts/ for more details.\n"
2304 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
2305 }
2306
ShowStyleEditor(ImGuiStyle * ref)2307 void ImGui::ShowStyleEditor(ImGuiStyle* ref)
2308 {
2309 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference)
2310 ImGuiStyle& style = ImGui::GetStyle();
2311 static ImGuiStyle ref_saved_style;
2312
2313 // Default to using internal storage as reference
2314 static bool init = true;
2315 if (init && ref == NULL)
2316 ref_saved_style = style;
2317 init = false;
2318 if (ref == NULL)
2319 ref = &ref_saved_style;
2320
2321 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
2322
2323 if (ImGui::ShowStyleSelector("Colors##Selector"))
2324 ref_saved_style = style;
2325 ImGui::ShowFontSelector("Fonts##Selector");
2326
2327 // Simplified Settings
2328 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
2329 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
2330 {
2331 bool window_border = (style.WindowBorderSize > 0.0f);
2332 if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f;
2333 }
2334 ImGui::SameLine();
2335 {
2336 bool frame_border = (style.FrameBorderSize > 0.0f);
2337 if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f;
2338 }
2339 ImGui::SameLine();
2340 {
2341 bool popup_border = (style.PopupBorderSize > 0.0f);
2342 if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f;
2343 }
2344
2345 // Save/Revert button
2346 if (ImGui::Button("Save Ref"))
2347 *ref = ref_saved_style = style;
2348 ImGui::SameLine();
2349 if (ImGui::Button("Revert Ref"))
2350 style = *ref;
2351 ImGui::SameLine();
2352 ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere.");
2353
2354 if (ImGui::TreeNode("Rendering"))
2355 {
2356 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
2357 ImGui::SameLine();
2358 ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
2359 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
2360 ImGui::PushItemWidth(100);
2361 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, NULL, 2.0f);
2362 if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f;
2363 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.
2364 ImGui::PopItemWidth();
2365 ImGui::TreePop();
2366 }
2367
2368 if (ImGui::TreeNode("Settings"))
2369 {
2370 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
2371 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f");
2372 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
2373 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
2374 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
2375 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
2376 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
2377 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
2378 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
2379 ImGui::Text("BorderSize");
2380 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
2381 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
2382 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
2383 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
2384 ImGui::Text("Rounding");
2385 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f");
2386 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f");
2387 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
2388 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
2389 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
2390 ImGui::Text("Alignment");
2391 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
2392 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
2393 ImGui::SameLine();
2394 ShowHelpMarker("Alignment applies when a button is larger than its text content.");
2395 ImGui::TreePop();
2396 }
2397
2398 if (ImGui::TreeNode("Colors"))
2399 {
2400 static int output_dest = 0;
2401 static bool output_only_modified = true;
2402 if (ImGui::Button("Export Unsaved"))
2403 {
2404 if (output_dest == 0)
2405 ImGui::LogToClipboard();
2406 else
2407 ImGui::LogToTTY();
2408 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
2409 for (int i = 0; i < ImGuiCol_COUNT; i++)
2410 {
2411 const ImVec4& col = style.Colors[i];
2412 const char* name = ImGui::GetStyleColorName(i);
2413 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
2414 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);
2415 }
2416 ImGui::LogFinish();
2417 }
2418 ImGui::SameLine();
2419 ImGui::PushItemWidth(120);
2420 ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
2421 ImGui::PopItemWidth();
2422 ImGui::SameLine();
2423 ImGui::Checkbox("Only Modified Colors", &output_only_modified);
2424
2425 ImGui::Text("Tip: Left-click on colored square to open color picker,\nRight-click to open edit options menu.");
2426
2427 static ImGuiTextFilter filter;
2428 filter.Draw("Filter colors", 200);
2429
2430 static ImGuiColorEditFlags alpha_flags = 0;
2431 ImGui::RadioButton("Opaque", &alpha_flags, 0);
2432 ImGui::SameLine();
2433 ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview);
2434 ImGui::SameLine();
2435 ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
2436
2437 ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
2438 ImGui::PushItemWidth(-160);
2439 for (int i = 0; i < ImGuiCol_COUNT; i++)
2440 {
2441 const char* name = ImGui::GetStyleColorName(i);
2442 if (!filter.PassFilter(name))
2443 continue;
2444 ImGui::PushID(i);
2445 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
2446 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
2447 {
2448 // 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.
2449 // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient!
2450 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
2451 if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i];
2452 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
2453 if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i];
2454 }
2455 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
2456 ImGui::TextUnformatted(name);
2457 ImGui::PopID();
2458 }
2459 ImGui::PopItemWidth();
2460 ImGui::EndChild();
2461
2462 ImGui::TreePop();
2463 }
2464
2465 bool fonts_opened = ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size);
2466 if (fonts_opened)
2467 {
2468 ImFontAtlas* atlas = ImGui::GetIO().Fonts;
2469 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
2470 {
2471 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
2472 ImGui::TreePop();
2473 }
2474 ImGui::PushItemWidth(100);
2475 for (int i = 0; i < atlas->Fonts.Size; i++)
2476 {
2477 ImFont* font = atlas->Fonts[i];
2478 ImGui::PushID(font);
2479 bool font_details_opened = ImGui::TreeNode(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size);
2480 ImGui::SameLine();
2481 if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font;
2482 if (font_details_opened)
2483 {
2484 ImGui::PushFont(font);
2485 ImGui::Text("The quick brown fox jumps over the lazy dog");
2486 ImGui::PopFont();
2487 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font
2488 ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, 0);
2489 ImGui::SameLine();
2490 ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)");
2491 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
2492 ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar);
2493 ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface));
2494 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
2495 {
2496 ImFontConfig* cfg = &font->ConfigData[config_i];
2497 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
2498 }
2499 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
2500 {
2501 // Display all glyphs of the fonts in separate pages of 256 characters
2502 const ImFontGlyph* glyph_fallback = font->FallbackGlyph; // Forcefully/dodgily make FindGlyph() return NULL on fallback, which isn't the default behavior.
2503 font->FallbackGlyph = NULL;
2504 for (int base = 0; base < 0x10000; base += 256)
2505 {
2506 int count = 0;
2507 for (int n = 0; n < 256; n++)
2508 count += font->FindGlyph((ImWchar)(base + n)) ? 1 : 0;
2509 if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
2510 {
2511 float cell_spacing = style.ItemSpacing.y;
2512 ImVec2 cell_size(font->FontSize * 1, font->FontSize * 1);
2513 ImVec2 base_pos = ImGui::GetCursorScreenPos();
2514 ImDrawList* draw_list = ImGui::GetWindowDrawList();
2515 for (int n = 0; n < 256; n++)
2516 {
2517 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size.x + cell_spacing), base_pos.y + (n / 16) * (cell_size.y + cell_spacing));
2518 ImVec2 cell_p2(cell_p1.x + cell_size.x, cell_p1.y + cell_size.y);
2519 const ImFontGlyph* glyph = font->FindGlyph((ImWchar)(base + n));
2520 ;
2521 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
2522 font->RenderChar(draw_list, cell_size.x, 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.
2523 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
2524 {
2525 ImGui::BeginTooltip();
2526 ImGui::Text("Codepoint: U+%04X", base + n);
2527 ImGui::Separator();
2528 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
2529 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
2530 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
2531 ImGui::EndTooltip();
2532 }
2533 }
2534 ImGui::Dummy(ImVec2((cell_size.x + cell_spacing) * 16, (cell_size.y + cell_spacing) * 16));
2535 ImGui::TreePop();
2536 }
2537 }
2538 font->FallbackGlyph = glyph_fallback;
2539 ImGui::TreePop();
2540 }
2541 ImGui::TreePop();
2542 }
2543 ImGui::PopID();
2544 }
2545 static float window_scale = 1.0f;
2546 ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window
2547 ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything
2548 ImGui::PopItemWidth();
2549 ImGui::SetWindowFontScale(window_scale);
2550 ImGui::TreePop();
2551 }
2552
2553 ImGui::PopItemWidth();
2554 }
2555
2556 // Demonstrate creating a fullscreen menu bar and populating it.
ShowExampleAppMainMenuBar()2557 static void ShowExampleAppMainMenuBar()
2558 {
2559 if (ImGui::BeginMainMenuBar())
2560 {
2561 if (ImGui::BeginMenu("File"))
2562 {
2563 ShowExampleMenuFile();
2564 ImGui::EndMenu();
2565 }
2566 if (ImGui::BeginMenu("Edit"))
2567 {
2568 if (ImGui::MenuItem("Undo", "CTRL+Z"))
2569 {
2570 }
2571 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false))
2572 {
2573 } // Disabled item
2574 ImGui::Separator();
2575 if (ImGui::MenuItem("Cut", "CTRL+X"))
2576 {
2577 }
2578 if (ImGui::MenuItem("Copy", "CTRL+C"))
2579 {
2580 }
2581 if (ImGui::MenuItem("Paste", "CTRL+V"))
2582 {
2583 }
2584 ImGui::EndMenu();
2585 }
2586 ImGui::EndMainMenuBar();
2587 }
2588 }
2589
ShowExampleMenuFile()2590 static void ShowExampleMenuFile()
2591 {
2592 ImGui::MenuItem("(dummy menu)", NULL, false, false);
2593 if (ImGui::MenuItem("New"))
2594 {
2595 }
2596 if (ImGui::MenuItem("Open", "Ctrl+O"))
2597 {
2598 }
2599 if (ImGui::BeginMenu("Open Recent"))
2600 {
2601 ImGui::MenuItem("fish_hat.c");
2602 ImGui::MenuItem("fish_hat.inl");
2603 ImGui::MenuItem("fish_hat.h");
2604 if (ImGui::BeginMenu("More.."))
2605 {
2606 ImGui::MenuItem("Hello");
2607 ImGui::MenuItem("Sailor");
2608 if (ImGui::BeginMenu("Recurse.."))
2609 {
2610 ShowExampleMenuFile();
2611 ImGui::EndMenu();
2612 }
2613 ImGui::EndMenu();
2614 }
2615 ImGui::EndMenu();
2616 }
2617 if (ImGui::MenuItem("Save", "Ctrl+S"))
2618 {
2619 }
2620 if (ImGui::MenuItem("Save As.."))
2621 {
2622 }
2623 ImGui::Separator();
2624 if (ImGui::BeginMenu("Options"))
2625 {
2626 static bool enabled = true;
2627 ImGui::MenuItem("Enabled", "", &enabled);
2628 ImGui::BeginChild("child", ImVec2(0, 60), true);
2629 for (int i = 0; i < 10; i++)
2630 ImGui::Text("Scrolling Text %d", i);
2631 ImGui::EndChild();
2632 static float f = 0.5f;
2633 static int n = 0;
2634 static bool b = true;
2635 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
2636 ImGui::InputFloat("Input", &f, 0.1f);
2637 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
2638 ImGui::Checkbox("Check", &b);
2639 ImGui::EndMenu();
2640 }
2641 if (ImGui::BeginMenu("Colors"))
2642 {
2643 float sz = ImGui::GetTextLineHeight();
2644 for (int i = 0; i < ImGuiCol_COUNT; i++)
2645 {
2646 const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
2647 ImVec2 p = ImGui::GetCursorScreenPos();
2648 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
2649 ImGui::Dummy(ImVec2(sz, sz));
2650 ImGui::SameLine();
2651 ImGui::MenuItem(name);
2652 }
2653 ImGui::EndMenu();
2654 }
2655 if (ImGui::BeginMenu("Disabled", false)) // Disabled
2656 {
2657 IM_ASSERT(0);
2658 }
2659 if (ImGui::MenuItem("Checked", NULL, true))
2660 {
2661 }
2662 if (ImGui::MenuItem("Quit", "Alt+F4"))
2663 {
2664 }
2665 }
2666
2667 // Demonstrate creating a window which gets auto-resized according to its content.
ShowExampleAppAutoResize(bool * p_open)2668 static void ShowExampleAppAutoResize(bool* p_open)
2669 {
2670 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
2671 {
2672 ImGui::End();
2673 return;
2674 }
2675
2676 static int lines = 10;
2677 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.");
2678 ImGui::SliderInt("Number of lines", &lines, 1, 20);
2679 for (int i = 0; i < lines; i++)
2680 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
2681 ImGui::End();
2682 }
2683
2684 // Demonstrate creating a window with custom resize constraints.
ShowExampleAppConstrainedResize(bool * p_open)2685 static void ShowExampleAppConstrainedResize(bool* p_open)
2686 {
2687 struct CustomConstraints // Helper functions to demonstrate programmatic constraints
2688 {
2689 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); }
2690 static void Step(ImGuiSizeCallbackData* data)
2691 {
2692 float step = (float)(int)(intptr_t)data->UserData;
2693 data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step);
2694 }
2695 };
2696
2697 static bool auto_resize = false;
2698 static int type = 0;
2699 static int display_lines = 10;
2700 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only
2701 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only
2702 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
2703 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500
2704 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500
2705 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
2706 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100); // Fixed Step
2707
2708 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
2709 if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
2710 {
2711 const char* desc[] =
2712 {
2713 "Resize vertical only",
2714 "Resize horizontal only",
2715 "Width > 100, Height > 100",
2716 "Width 400-500",
2717 "Height 400-500",
2718 "Custom: Always Square",
2719 "Custom: Fixed Steps (100)",
2720 };
2721 if (ImGui::Button("200x200"))
2722 {
2723 ImGui::SetWindowSize(ImVec2(200, 200));
2724 }
2725 ImGui::SameLine();
2726 if (ImGui::Button("500x500"))
2727 {
2728 ImGui::SetWindowSize(ImVec2(500, 500));
2729 }
2730 ImGui::SameLine();
2731 if (ImGui::Button("800x200"))
2732 {
2733 ImGui::SetWindowSize(ImVec2(800, 200));
2734 }
2735 ImGui::PushItemWidth(200);
2736 ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc));
2737 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
2738 ImGui::PopItemWidth();
2739 ImGui::Checkbox("Auto-resize", &auto_resize);
2740 for (int i = 0; i < display_lines; i++)
2741 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
2742 }
2743 ImGui::End();
2744 }
2745
2746 // Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use.
ShowExampleAppFixedOverlay(bool * p_open)2747 static void ShowExampleAppFixedOverlay(bool* p_open)
2748 {
2749 const float DISTANCE = 10.0f;
2750 static int corner = 0;
2751 ImVec2 window_pos = ImVec2((corner & 1) ? ImGui::GetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? ImGui::GetIO().DisplaySize.y - DISTANCE : DISTANCE);
2752 ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
2753 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
2754 ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
2755 if (ImGui::Begin("Example: Fixed Overlay", p_open, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
2756 {
2757 ImGui::Text("Simple overlay\nin the corner of the screen.\n(right-click to change position)");
2758 ImGui::Separator();
2759 ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y);
2760 if (ImGui::BeginPopupContextWindow())
2761 {
2762 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0;
2763 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1;
2764 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2;
2765 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3;
2766 if (p_open && ImGui::MenuItem("Close")) *p_open = false;
2767 ImGui::EndPopup();
2768 }
2769 ImGui::End();
2770 }
2771 }
2772
2773 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation.
2774 // This apply to 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 *)2775 static void ShowExampleAppWindowTitles(bool*)
2776 {
2777 // By default, Windows are uniquely identified by their title.
2778 // You can use the "##" and "###" markers to manipulate the display/ID.
2779
2780 // Using "##" to display same title but have unique identifier.
2781 ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
2782 ImGui::Begin("Same title as another window##1");
2783 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
2784 ImGui::End();
2785
2786 ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver);
2787 ImGui::Begin("Same title as another window##2");
2788 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
2789 ImGui::End();
2790
2791 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
2792 char buf[128];
2793 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
2794 ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver);
2795 ImGui::Begin(buf);
2796 ImGui::Text("This window has a changing title.");
2797 ImGui::End();
2798 }
2799
2800 // Demonstrate using the low-level ImDrawList to draw custom shapes.
ShowExampleAppCustomRendering(bool * p_open)2801 static void ShowExampleAppCustomRendering(bool* p_open)
2802 {
2803 ImGui::SetNextWindowSize(ImVec2(350, 560), ImGuiCond_FirstUseEver);
2804 if (!ImGui::Begin("Example: Custom rendering", p_open))
2805 {
2806 ImGui::End();
2807 return;
2808 }
2809
2810 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc.
2811 // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4.
2812 // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types)
2813 // In this example we are not using the maths operators!
2814 ImDrawList* draw_list = ImGui::GetWindowDrawList();
2815
2816 // Primitives
2817 ImGui::Text("Primitives");
2818 static float sz = 36.0f;
2819 static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
2820 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
2821 ImGui::ColorEdit3("Color", &col.x);
2822 {
2823 const ImVec2 p = ImGui::GetCursorScreenPos();
2824 const ImU32 col32 = ImColor(col);
2825 float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f;
2826 for (int n = 0; n < 2; n++)
2827 {
2828 float thickness = (n == 0) ? 1.0f : 4.0f;
2829 draw_list->AddCircle(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col32, 20, thickness);
2830 x += sz + spacing;
2831 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 0.0f, ImDrawCornerFlags_All, thickness);
2832 x += sz + spacing;
2833 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_All, thickness);
2834 x += sz + spacing;
2835 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight, thickness);
2836 x += sz + spacing;
2837 draw_list->AddTriangle(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32, thickness);
2838 x += sz + spacing;
2839 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col32, thickness);
2840 x += sz + spacing;
2841 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, thickness);
2842 x += sz + spacing;
2843 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col32, thickness);
2844 x += spacing;
2845 draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz * 1.3f, y + sz * 0.3f), ImVec2(x + sz - sz * 1.3f, y + sz - sz * 0.3f), ImVec2(x + sz, y + sz), col32, thickness);
2846 x = p.x + 4;
2847 y += sz + spacing;
2848 }
2849 draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz * 0.5f, col32, 32);
2850 x += sz + spacing;
2851 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32);
2852 x += sz + spacing;
2853 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f);
2854 x += sz + spacing;
2855 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight);
2856 x += sz + spacing;
2857 draw_list->AddTriangleFilled(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32);
2858 x += sz + spacing;
2859 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));
2860 ImGui::Dummy(ImVec2((sz + spacing) * 8, (sz + spacing) * 3));
2861 }
2862 ImGui::Separator();
2863 {
2864 static ImVector<ImVec2> points;
2865 static bool adding_line = false;
2866 ImGui::Text("Canvas example");
2867 if (ImGui::Button("Clear")) points.clear();
2868 if (points.Size >= 2)
2869 {
2870 ImGui::SameLine();
2871 if (ImGui::Button("Undo"))
2872 {
2873 points.pop_back();
2874 points.pop_back();
2875 }
2876 }
2877 ImGui::Text("Left-click and drag to add lines,\nRight-click to undo");
2878
2879 // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered()
2880 // However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos().
2881 // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max).
2882 ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
2883 ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
2884 if (canvas_size.x < 50.0f) canvas_size.x = 50.0f;
2885 if (canvas_size.y < 50.0f) canvas_size.y = 50.0f;
2886 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));
2887 draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255));
2888
2889 bool adding_preview = false;
2890 ImGui::InvisibleButton("canvas", canvas_size);
2891 ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
2892 if (adding_line)
2893 {
2894 adding_preview = true;
2895 points.push_back(mouse_pos_in_canvas);
2896 if (!ImGui::IsMouseDown(0))
2897 adding_line = adding_preview = false;
2898 }
2899 if (ImGui::IsItemHovered())
2900 {
2901 if (!adding_line && ImGui::IsMouseClicked(0))
2902 {
2903 points.push_back(mouse_pos_in_canvas);
2904 adding_line = true;
2905 }
2906 if (ImGui::IsMouseClicked(1) && !points.empty())
2907 {
2908 adding_line = adding_preview = false;
2909 points.pop_back();
2910 points.pop_back();
2911 }
2912 }
2913 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.)
2914 for (int i = 0; i < points.Size - 1; i += 2)
2915 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);
2916 draw_list->PopClipRect();
2917 if (adding_preview)
2918 points.pop_back();
2919 }
2920 ImGui::End();
2921 }
2922
2923 // Demonstrating creating a simple console window, with scrolling, filtering, completion and history.
2924 // For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions.
2925 struct ExampleAppConsole
2926 {
2927 char InputBuf[256];
2928 ImVector<char*> Items;
2929 bool ScrollToBottom;
2930 ImVector<char*> History;
2931 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
2932 ImVector<const char*> Commands;
2933
ExampleAppConsoleExampleAppConsole2934 ExampleAppConsole()
2935 {
2936 ClearLog();
2937 memset(InputBuf, 0, sizeof(InputBuf));
2938 HistoryPos = -1;
2939 Commands.push_back("HELP");
2940 Commands.push_back("HISTORY");
2941 Commands.push_back("CLEAR");
2942 Commands.push_back("CLASSIFY"); // "classify" is here to provide an example of "C"+[tab] completing to "CL" and displaying matches.
2943 AddLog("Welcome to ImGui!");
2944 }
~ExampleAppConsoleExampleAppConsole2945 ~ExampleAppConsole()
2946 {
2947 ClearLog();
2948 for (int i = 0; i < History.Size; i++)
2949 free(History[i]);
2950 }
2951
2952 // Portable helpers
StricmpExampleAppConsole2953 static int Stricmp(const char* str1, const char* str2)
2954 {
2955 int d;
2956 while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1)
2957 {
2958 str1++;
2959 str2++;
2960 }
2961 return d;
2962 }
StrnicmpExampleAppConsole2963 static int Strnicmp(const char* str1, const char* str2, int n)
2964 {
2965 int d = 0;
2966 while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1)
2967 {
2968 str1++;
2969 str2++;
2970 n--;
2971 }
2972 return d;
2973 }
StrdupExampleAppConsole2974 static char* Strdup(const char* str)
2975 {
2976 size_t len = strlen(str) + 1;
2977 void* buff = malloc(len);
2978 return (char*)memcpy(buff, (const void*)str, len);
2979 }
2980
ClearLogExampleAppConsole2981 void ClearLog()
2982 {
2983 for (int i = 0; i < Items.Size; i++)
2984 free(Items[i]);
2985 Items.clear();
2986 ScrollToBottom = true;
2987 }
2988
AddLogExampleAppConsole2989 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
2990 {
2991 // FIXME-OPT
2992 char buf[1024];
2993 va_list args;
2994 va_start(args, fmt);
2995 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
2996 buf[IM_ARRAYSIZE(buf) - 1] = 0;
2997 va_end(args);
2998 Items.push_back(Strdup(buf));
2999 ScrollToBottom = true;
3000 }
3001
DrawExampleAppConsole3002 void Draw(const char* title, bool* p_open)
3003 {
3004 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
3005 if (!ImGui::Begin(title, p_open))
3006 {
3007 ImGui::End();
3008 return;
3009 }
3010
3011 // 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.
3012 // Here we create a context menu only available from the title bar.
3013 if (ImGui::BeginPopupContextItem())
3014 {
3015 if (ImGui::MenuItem("Close"))
3016 *p_open = false;
3017 ImGui::EndPopup();
3018 }
3019
3020 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.");
3021 ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion.");
3022
3023 // TODO: display items starting from the bottom
3024
3025 if (ImGui::SmallButton("Add Dummy Text"))
3026 {
3027 AddLog("%d some text", Items.Size);
3028 AddLog("some more text");
3029 AddLog("display very important message here!");
3030 }
3031 ImGui::SameLine();
3032 if (ImGui::SmallButton("Add Dummy Error"))
3033 {
3034 AddLog("[error] something went wrong");
3035 }
3036 ImGui::SameLine();
3037 if (ImGui::SmallButton("Clear"))
3038 {
3039 ClearLog();
3040 }
3041 ImGui::SameLine();
3042 bool copy_to_clipboard = ImGui::SmallButton("Copy");
3043 ImGui::SameLine();
3044 if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true;
3045 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
3046
3047 ImGui::Separator();
3048
3049 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
3050 static ImGuiTextFilter filter;
3051 filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
3052 ImGui::PopStyleVar();
3053 ImGui::Separator();
3054
3055 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text
3056 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText
3057 if (ImGui::BeginPopupContextWindow())
3058 {
3059 if (ImGui::Selectable("Clear")) ClearLog();
3060 ImGui::EndPopup();
3061 }
3062
3063 // 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());
3064 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items.
3065 // 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.
3066 // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with:
3067 // ImGuiListClipper clipper(Items.Size);
3068 // while (clipper.Step())
3069 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
3070 // However take 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.
3071 // 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,
3072 // 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!
3073 // 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.
3074 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
3075 if (copy_to_clipboard)
3076 ImGui::LogToClipboard();
3077 ImVec4 col_default_text = ImGui::GetStyleColorVec4(ImGuiCol_Text);
3078 for (int i = 0; i < Items.Size; i++)
3079 {
3080 const char* item = Items[i];
3081 if (!filter.PassFilter(item))
3082 continue;
3083 ImVec4 col = col_default_text;
3084 if (strstr(item, "[error]"))
3085 col = ImColor(1.0f, 0.4f, 0.4f, 1.0f);
3086 else if (strncmp(item, "# ", 2) == 0)
3087 col = ImColor(1.0f, 0.78f, 0.58f, 1.0f);
3088 ImGui::PushStyleColor(ImGuiCol_Text, col);
3089 ImGui::TextUnformatted(item);
3090 ImGui::PopStyleColor();
3091 }
3092 if (copy_to_clipboard)
3093 ImGui::LogFinish();
3094 if (ScrollToBottom)
3095 ImGui::SetScrollHere();
3096 ScrollToBottom = false;
3097 ImGui::PopStyleVar();
3098 ImGui::EndChild();
3099 ImGui::Separator();
3100
3101 // Command-line
3102 bool reclaim_focus = false;
3103 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this))
3104 {
3105 char* input_end = InputBuf + strlen(InputBuf);
3106 while (input_end > InputBuf && input_end[-1] == ' ')
3107 {
3108 input_end--;
3109 }
3110 *input_end = 0;
3111 if (InputBuf[0])
3112 ExecCommand(InputBuf);
3113 strcpy(InputBuf, "");
3114 reclaim_focus = true;
3115 }
3116
3117 // Demonstrate keeping focus on the input box
3118 ImGui::SetItemDefaultFocus();
3119 if (reclaim_focus)
3120 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
3121
3122 ImGui::End();
3123 }
3124
ExecCommandExampleAppConsole3125 void ExecCommand(const char* command_line)
3126 {
3127 AddLog("# %s\n", command_line);
3128
3129 // 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.
3130 HistoryPos = -1;
3131 for (int i = History.Size - 1; i >= 0; i--)
3132 if (Stricmp(History[i], command_line) == 0)
3133 {
3134 free(History[i]);
3135 History.erase(History.begin() + i);
3136 break;
3137 }
3138 History.push_back(Strdup(command_line));
3139
3140 // Process command
3141 if (Stricmp(command_line, "CLEAR") == 0)
3142 {
3143 ClearLog();
3144 }
3145 else if (Stricmp(command_line, "HELP") == 0)
3146 {
3147 AddLog("Commands:");
3148 for (int i = 0; i < Commands.Size; i++)
3149 AddLog("- %s", Commands[i]);
3150 }
3151 else if (Stricmp(command_line, "HISTORY") == 0)
3152 {
3153 int first = History.Size - 10;
3154 for (int i = first > 0 ? first : 0; i < History.Size; i++)
3155 AddLog("%3d: %s\n", i, History[i]);
3156 }
3157 else
3158 {
3159 AddLog("Unknown command: '%s'\n", command_line);
3160 }
3161 }
3162
TextEditCallbackStubExampleAppConsole3163 static int TextEditCallbackStub(ImGuiTextEditCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks
3164 {
3165 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
3166 return console->TextEditCallback(data);
3167 }
3168
TextEditCallbackExampleAppConsole3169 int TextEditCallback(ImGuiTextEditCallbackData* data)
3170 {
3171 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
3172 switch (data->EventFlag)
3173 {
3174 case ImGuiInputTextFlags_CallbackCompletion:
3175 {
3176 // Example of TEXT COMPLETION
3177
3178 // Locate beginning of current word
3179 const char* word_end = data->Buf + data->CursorPos;
3180 const char* word_start = word_end;
3181 while (word_start > data->Buf)
3182 {
3183 const char c = word_start[-1];
3184 if (c == ' ' || c == '\t' || c == ',' || c == ';')
3185 break;
3186 word_start--;
3187 }
3188
3189 // Build a list of candidates
3190 ImVector<const char*> candidates;
3191 for (int i = 0; i < Commands.Size; i++)
3192 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
3193 candidates.push_back(Commands[i]);
3194
3195 if (candidates.Size == 0)
3196 {
3197 // No match
3198 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
3199 }
3200 else if (candidates.Size == 1)
3201 {
3202 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing
3203 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
3204 data->InsertChars(data->CursorPos, candidates[0]);
3205 data->InsertChars(data->CursorPos, " ");
3206 }
3207 else
3208 {
3209 // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY"
3210 int match_len = (int)(word_end - word_start);
3211 for (;;)
3212 {
3213 int c = 0;
3214 bool all_candidates_matches = true;
3215 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
3216 if (i == 0)
3217 c = toupper(candidates[i][match_len]);
3218 else if (c == 0 || c != toupper(candidates[i][match_len]))
3219 all_candidates_matches = false;
3220 if (!all_candidates_matches)
3221 break;
3222 match_len++;
3223 }
3224
3225 if (match_len > 0)
3226 {
3227 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
3228 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
3229 }
3230
3231 // List matches
3232 AddLog("Possible matches:\n");
3233 for (int i = 0; i < candidates.Size; i++)
3234 AddLog("- %s\n", candidates[i]);
3235 }
3236
3237 break;
3238 }
3239 case ImGuiInputTextFlags_CallbackHistory:
3240 {
3241 // Example of HISTORY
3242 const int prev_history_pos = HistoryPos;
3243 if (data->EventKey == ImGuiKey_UpArrow)
3244 {
3245 if (HistoryPos == -1)
3246 HistoryPos = History.Size - 1;
3247 else if (HistoryPos > 0)
3248 HistoryPos--;
3249 }
3250 else if (data->EventKey == ImGuiKey_DownArrow)
3251 {
3252 if (HistoryPos != -1)
3253 if (++HistoryPos >= History.Size)
3254 HistoryPos = -1;
3255 }
3256
3257 // A better implementation would preserve the data on the current input line along with cursor position.
3258 if (prev_history_pos != HistoryPos)
3259 {
3260 data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = (int)snprintf(data->Buf, (size_t)data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : "");
3261 data->BufDirty = true;
3262 }
3263 }
3264 }
3265 return 0;
3266 }
3267 };
3268
ShowExampleAppConsole(bool * p_open)3269 static void ShowExampleAppConsole(bool* p_open)
3270 {
3271 static ExampleAppConsole console;
3272 console.Draw("Example: Console", p_open);
3273 }
3274
3275 // Usage:
3276 // static ExampleAppLog my_log;
3277 // my_log.AddLog("Hello %d world\n", 123);
3278 // my_log.Draw("title");
3279 struct ExampleAppLog
3280 {
3281 ImGuiTextBuffer Buf;
3282 ImGuiTextFilter Filter;
3283 ImVector<int> LineOffsets; // Index to lines offset
3284 bool ScrollToBottom;
3285
ClearExampleAppLog3286 void Clear()
3287 {
3288 Buf.clear();
3289 LineOffsets.clear();
3290 }
3291
AddLogExampleAppLog3292 void AddLog(const char* fmt, ...) IM_FMTARGS(2)
3293 {
3294 int old_size = Buf.size();
3295 va_list args;
3296 va_start(args, fmt);
3297 Buf.appendfv(fmt, args);
3298 va_end(args);
3299 for (int new_size = Buf.size(); old_size < new_size; old_size++)
3300 if (Buf[old_size] == '\n')
3301 LineOffsets.push_back(old_size);
3302 ScrollToBottom = true;
3303 }
3304
DrawExampleAppLog3305 void Draw(const char* title, bool* p_open = NULL)
3306 {
3307 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
3308 ImGui::Begin(title, p_open);
3309 if (ImGui::Button("Clear")) Clear();
3310 ImGui::SameLine();
3311 bool copy = ImGui::Button("Copy");
3312 ImGui::SameLine();
3313 Filter.Draw("Filter", -100.0f);
3314 ImGui::Separator();
3315 ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
3316 if (copy) ImGui::LogToClipboard();
3317
3318 if (Filter.IsActive())
3319 {
3320 const char* buf_begin = Buf.begin();
3321 const char* line = buf_begin;
3322 for (int line_no = 0; line != NULL; line_no++)
3323 {
3324 const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL;
3325 if (Filter.PassFilter(line, line_end))
3326 ImGui::TextUnformatted(line, line_end);
3327 line = line_end && line_end[1] ? line_end + 1 : NULL;
3328 }
3329 }
3330 else
3331 {
3332 ImGui::TextUnformatted(Buf.begin());
3333 }
3334
3335 if (ScrollToBottom)
3336 ImGui::SetScrollHere(1.0f);
3337 ScrollToBottom = false;
3338 ImGui::EndChild();
3339 ImGui::End();
3340 }
3341 };
3342
3343 // Demonstrate creating a simple log window with basic filtering.
ShowExampleAppLog(bool * p_open)3344 static void ShowExampleAppLog(bool* p_open)
3345 {
3346 static ExampleAppLog log;
3347
3348 // Demo: add random items (unless Ctrl is held)
3349 static float last_time = -1.0f;
3350 float time = ImGui::GetTime();
3351 if (time - last_time >= 0.20f && !ImGui::GetIO().KeyCtrl)
3352 {
3353 const char* random_words[] = {"system", "info", "warning", "error", "fatal", "notice", "log"};
3354 log.AddLog("[%s] Hello, time is %.1f, frame count is %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, ImGui::GetFrameCount());
3355 last_time = time;
3356 }
3357
3358 log.Draw("Example: Log", p_open);
3359 }
3360
3361 // Demonstrate create a window with multiple child windows.
ShowExampleAppLayout(bool * p_open)3362 static void ShowExampleAppLayout(bool* p_open)
3363 {
3364 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
3365 if (ImGui::Begin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar))
3366 {
3367 if (ImGui::BeginMenuBar())
3368 {
3369 if (ImGui::BeginMenu("File"))
3370 {
3371 if (ImGui::MenuItem("Close")) *p_open = false;
3372 ImGui::EndMenu();
3373 }
3374 ImGui::EndMenuBar();
3375 }
3376
3377 // left
3378 static int selected = 0;
3379 ImGui::BeginChild("left pane", ImVec2(150, 0), true);
3380 for (int i = 0; i < 100; i++)
3381 {
3382 char label[128];
3383 sprintf(label, "MyObject %d", i);
3384 if (ImGui::Selectable(label, selected == i))
3385 selected = i;
3386 }
3387 ImGui::EndChild();
3388 ImGui::SameLine();
3389
3390 // right
3391 ImGui::BeginGroup();
3392 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
3393 ImGui::Text("MyObject: %d", selected);
3394 ImGui::Separator();
3395 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
3396 ImGui::EndChild();
3397 if (ImGui::Button("Revert"))
3398 {
3399 }
3400 ImGui::SameLine();
3401 if (ImGui::Button("Save"))
3402 {
3403 }
3404 ImGui::EndGroup();
3405 }
3406 ImGui::End();
3407 }
3408
3409 // Demonstrate create a simple property editor.
ShowExampleAppPropertyEditor(bool * p_open)3410 static void ShowExampleAppPropertyEditor(bool* p_open)
3411 {
3412 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
3413 if (!ImGui::Begin("Example: Property editor", p_open))
3414 {
3415 ImGui::End();
3416 return;
3417 }
3418
3419 ShowHelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API.");
3420
3421 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
3422 ImGui::Columns(2);
3423 ImGui::Separator();
3424
3425 struct funcs
3426 {
3427 static void ShowDummyObject(const char* prefix, int uid)
3428 {
3429 ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
3430 ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high.
3431 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
3432 ImGui::NextColumn();
3433 ImGui::AlignTextToFramePadding();
3434 ImGui::Text("my sailor is rich");
3435 ImGui::NextColumn();
3436 if (node_open)
3437 {
3438 static float dummy_members[8] = {0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f};
3439 for (int i = 0; i < 8; i++)
3440 {
3441 ImGui::PushID(i); // Use field index as identifier.
3442 if (i < 2)
3443 {
3444 ShowDummyObject("Child", 424242);
3445 }
3446 else
3447 {
3448 ImGui::AlignTextToFramePadding();
3449 // Here we use a Selectable (instead of Text) to highlight on hover
3450 //ImGui::Text("Field_%d", i);
3451 char label[32];
3452 sprintf(label, "Field_%d", i);
3453 ImGui::Bullet();
3454 ImGui::Selectable(label);
3455 ImGui::NextColumn();
3456 ImGui::PushItemWidth(-1);
3457 if (i >= 5)
3458 ImGui::InputFloat("##value", &dummy_members[i], 1.0f);
3459 else
3460 ImGui::DragFloat("##value", &dummy_members[i], 0.01f);
3461 ImGui::PopItemWidth();
3462 ImGui::NextColumn();
3463 }
3464 ImGui::PopID();
3465 }
3466 ImGui::TreePop();
3467 }
3468 ImGui::PopID();
3469 }
3470 };
3471
3472 // Iterate dummy objects with dummy members (all the same data)
3473 for (int obj_i = 0; obj_i < 3; obj_i++)
3474 funcs::ShowDummyObject("Object", obj_i);
3475
3476 ImGui::Columns(1);
3477 ImGui::Separator();
3478 ImGui::PopStyleVar();
3479 ImGui::End();
3480 }
3481
3482 // Demonstrate/test rendering huge amount of text, and the incidence of clipping.
ShowExampleAppLongText(bool * p_open)3483 static void ShowExampleAppLongText(bool* p_open)
3484 {
3485 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
3486 if (!ImGui::Begin("Example: Long text display", p_open))
3487 {
3488 ImGui::End();
3489 return;
3490 }
3491
3492 static int test_type = 0;
3493 static ImGuiTextBuffer log;
3494 static int lines = 0;
3495 ImGui::Text("Printing unusually long amount of text.");
3496 ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0");
3497 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
3498 if (ImGui::Button("Clear"))
3499 {
3500 log.clear();
3501 lines = 0;
3502 }
3503 ImGui::SameLine();
3504 if (ImGui::Button("Add 1000 lines"))
3505 {
3506 for (int i = 0; i < 1000; i++)
3507 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
3508 lines += 1000;
3509 }
3510 ImGui::BeginChild("Log");
3511 switch (test_type)
3512 {
3513 case 0:
3514 // Single call to TextUnformatted() with a big buffer
3515 ImGui::TextUnformatted(log.begin(), log.end());
3516 break;
3517 case 1:
3518 {
3519 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
3520 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
3521 ImGuiListClipper clipper(lines);
3522 while (clipper.Step())
3523 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
3524 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
3525 ImGui::PopStyleVar();
3526 break;
3527 }
3528 case 2:
3529 // Multiple calls to Text(), not clipped (slow)
3530 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
3531 for (int i = 0; i < lines; i++)
3532 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
3533 ImGui::PopStyleVar();
3534 break;
3535 }
3536 ImGui::EndChild();
3537 ImGui::End();
3538 }
3539
3540 // End of Demo code
3541 #else
3542
ShowDemoWindow(bool *)3543 void ImGui::ShowDemoWindow(bool*) {}
ShowUserGuide()3544 void ImGui::ShowUserGuide() {}
ShowStyleEditor(ImGuiStyle *)3545 void ImGui::ShowStyleEditor(ImGuiStyle*) {}
3546
3547 #endif
3548