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