source: opengl-game/imgui_demo.cpp@ 54b6d6b

feature/imgui-sdl points-test
Last change on this file since 54b6d6b was 4e0b82b, checked in by Dmitry Portnoy <dmp1488@…>, 7 years ago

Add an ImGui example project

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