1 module imgui_demo;
2 
3 // dear imgui, v1.51
4 // (demo code)
5 
6 // Message to the person tempted to delete this file when integrating ImGui into their code base:
7 // 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.
8 // Everything in this file will be stripped out by the linker if you don't call igShowDemoWindow().
9 // During development, you can call igShowDemoWindow() in your code to learn about various features of ImGui. Have it wired in a debug menu!
10 // 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.
11 // Note that you can #define IMGUI_DISABLE_TEST_WINDOWS in imconfig.h for the same effect.
12 // If you want to link core ImGui in your public builds but not those test windows, #define IMGUI_DISABLE_TEST_WINDOWS in imconfig.h and those functions will be empty.
13 // For any other case, if you have ImGui available you probably want this to be available for reference and execution.
14 // Thank you,
15 // -Your beloved friend, imgui_demo.cpp (that you won't delete)
16 
17 // Message to beginner C/C++ programmer about the meaning of 'static': in this demo code, we frequently we use 'static' variables inside functions. 
18 // We do this as a way to gather code and data in the same place, make the demo code faster to read, faster to write, and smaller. A static variable persist across calls, 
19 // so it is essentially like a global variable but declared inside the scope of the function.
20 // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant or used in threads.
21 // This may be a pattern you want to use in your code (simple is beautiful!), but most of the real data you would be editing is likely to be stored outside your function.
22 
23 import derelict.imgui.imgui;
24 
25 import std.string;
26 import std.format;
27 import std.conv : to;
28 import std.algorithm : max;
29 import std.algorithm.mutation : remove;
30 import std.math : isNaN;
31 import std.uni : icmp;
32 import core.stdc.stdint : intptr_t;
33 import core.stdc.string : memset, strchr, strcpy, strncmp, memcmp, memcpy, strlen, strstr;
34 import core.stdc.float_ : FLT_MAX;
35 import core.stdc.stdlib : rand;
36 import core.stdc.ctype : toupper;
37 import core.stdc.stdio : printf, snprintf, sprintf;
38 import core.stdc.math : cosf, sinf, sqrtf;
39 import core.stdc.stdarg : va_list, va_end, va_start;
40 import core.vararg;
41 
42 // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
43 version(Windows) {
44     enum IM_NEWLINE = "\r\n";
45 } else {
46     enum IM_NEWLINE = "\n";
47 }
48 
49 size_t IM_ARRAYSIZE(T)(T _ARR) { return _ARR.length; }
50 alias IM_MAX = max;
51 
52 //-----------------------------------------------------------------------------
53 // DEMO CODE
54 //-----------------------------------------------------------------------------
55 
56 void ShowHelpMarker(string desc)
57 {
58     igTextDisabled("(?)");
59     if (igIsItemHovered())
60     {
61         igBeginTooltip();
62         igPushTextWrapPos(450.0f);
63         igTextUnformatted(desc.ptr, desc.ptr + desc.length);
64         igPopTextWrapPos();
65         igEndTooltip();
66     }
67 }
68 
69 void igShowUserGuide()
70 {
71     igBulletText("Double-click on title bar to collapse window.");
72     igBulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents).");
73     igBulletText("Click and drag on any empty space to move window.");
74     igBulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
75     igBulletText("CTRL+Click on a slider or drag box to input value as text.");
76     if (igGetIO().FontAllowUserScaling)
77         igBulletText("CTRL+Mouse Wheel to zoom window contents.");
78     igBulletText("Mouse Wheel to scroll.");
79     igBulletText("While editing text:\n");
80     igIndent();
81     igBulletText("Hold SHIFT or use mouse to select text.");
82     igBulletText("CTRL+Left/Right to word jump.");
83     igBulletText("CTRL+A or double-click to select all.");
84     igBulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard.");
85     igBulletText("CTRL+Z,CTRL+Y to undo/redo.");
86     igBulletText("ESCAPE to revert.");
87     igBulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
88     igUnindent();
89 }
90 
91 // Demonstrate most ImGui features (big function!)
92 void igShowDemoWindow(bool* p_open)
93 {
94     // Examples apps
95     static bool show_app_main_menu_bar = false;
96     static bool show_app_console = false;
97     static bool show_app_log = false;
98     static bool show_app_layout = false;
99     static bool show_app_property_editor = false;
100     static bool show_app_long_text = false;
101     static bool show_app_auto_resize = false;
102     static bool show_app_constrained_resize = false;
103     static bool show_app_fixed_overlay = false;
104     static bool show_app_manipulating_window_title = false;
105     static bool show_app_custom_rendering = false;
106     static bool show_app_style_editor = false;
107 
108     static bool show_app_metrics = false;
109     static bool show_app_about = false;
110 
111     if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
112     if (show_app_console) ShowExampleAppConsole(&show_app_console);
113     if (show_app_log) ShowExampleAppLog(&show_app_log);
114     if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
115     if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
116     if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
117     if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
118     if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
119     if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay);
120     if (show_app_manipulating_window_title) ShowExampleAppManipulatingWindowTitle(&show_app_manipulating_window_title);
121     if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
122 
123     if (show_app_metrics) igShowMetricsWindow(&show_app_metrics);
124     if (show_app_style_editor) { igBegin("Style Editor", &show_app_style_editor); igShowStyleEditor(); igEnd(); }
125     if (show_app_about)
126     {
127         igBegin("About Dear ImGui", &show_app_about, ImGuiWindowFlags_AlwaysAutoResize);
128         igText("dear imgui, %s", igGetVersion());
129         igSeparator();
130         igText("By Omar Cornut and all github contributors.");
131         igText("ImGui is licensed under the MIT License, see LICENSE for more information.");
132         igEnd();
133     }
134 
135     static bool no_titlebar = false;
136     static bool no_border = true;
137     static bool no_resize = false;
138     static bool no_move = false;
139     static bool no_scrollbar = false;
140     static bool no_collapse = false;
141     static bool no_menu = false;
142     static bool no_close = false;
143 
144     // Demonstrate the various window flags. Typically you would just use the default.
145     ImGuiWindowFlags window_flags = 0;
146     if (no_titlebar)  window_flags |= ImGuiWindowFlags_NoTitleBar;
147     if (!no_border)   window_flags |= ImGuiWindowFlags_ShowBorders;
148     if (no_resize)    window_flags |= ImGuiWindowFlags_NoResize;
149     if (no_move)      window_flags |= ImGuiWindowFlags_NoMove;
150     if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
151     if (no_collapse)  window_flags |= ImGuiWindowFlags_NoCollapse;
152     if (!no_menu)     window_flags |= ImGuiWindowFlags_MenuBar;
153     if (no_close)     p_open = null;
154 
155     igSetNextWindowSize(ImVec2(550,680), ImGuiCond_FirstUseEver);
156     if (!igBegin("[D]ImGui Demo", p_open, window_flags))
157     {
158         // Early out if the window is collapsed, as an optimization.
159         igEnd();
160         return;
161     }
162 
163     //igPushItemWidth(igGetWindowWidth() * 0.65f);    // 2/3 of the space for widget and 1/3 for labels
164     igPushItemWidth(-140);                                 // Right align, keep 140 pixels for labels
165 
166     igText("dear imgui says hello. (%s)", igGetVersion());
167 
168     // Menu
169     if (igBeginMenuBar())
170     {
171         if (igBeginMenu("Menu"))
172         {
173             ShowExampleMenuFile();
174             igEndMenu();
175         }
176         if (igBeginMenu("Examples"))
177         {
178             igMenuItemPtr("Main menu bar", null, &show_app_main_menu_bar);
179             igMenuItemPtr("Console", null, &show_app_console);
180             igMenuItemPtr("Log", null, &show_app_log);
181             igMenuItemPtr("Simple layout", null, &show_app_layout);
182             igMenuItemPtr("Property editor", null, &show_app_property_editor);
183             igMenuItemPtr("Long text display", null, &show_app_long_text);
184             igMenuItemPtr("Auto-resizing window", null, &show_app_auto_resize);
185             igMenuItemPtr("Constrained-resizing window", null, &show_app_constrained_resize);
186             igMenuItemPtr("Simple overlay", null, &show_app_fixed_overlay);
187             igMenuItemPtr("Manipulating window title", null, &show_app_manipulating_window_title);
188             igMenuItemPtr("Custom rendering", null, &show_app_custom_rendering);
189             igEndMenu();
190         }
191         if (igBeginMenu("Help"))
192         {
193             igMenuItemPtr("Metrics", null, &show_app_metrics);
194             igMenuItemPtr("Style Editor", null, &show_app_style_editor);
195             igMenuItemPtr("About ImGui", null, &show_app_about);
196             igEndMenu();
197         }
198         igEndMenuBar();
199     }
200 
201     igSpacing();
202     if (igCollapsingHeader("Help"))
203     {
204         igTextWrapped("This window is being created by the ShowDemoWindow() function. Please refer to the code in imgui_demo.d for programming reference.\n\n");
205         igText("USER GUIDE:");
206         igShowUserGuide();
207     }
208 
209     if (igCollapsingHeader("Window options"))
210     {
211         igCheckbox("No titlebar", &no_titlebar); igSameLine(150);
212         igCheckbox("No scrollbar", &no_scrollbar); igSameLine(300);
213         igCheckbox("No menu", &no_menu);
214         igCheckbox("No move", &no_move); igSameLine(150);
215         igCheckbox("No resize", &no_resize); igSameLine(300);
216         igCheckbox("No collapse", &no_collapse);
217         igCheckbox("No close", &no_close);
218 
219         if (igTreeNode("Style"))
220         {
221             igShowStyleEditor();
222             igTreePop();
223         }
224 
225         if (igTreeNode("Capture/Logging"))
226         {
227             igTextWrapped("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 igLogText() to output directly to the log without a visual output.");
228             igLogButtons();
229             igTreePop();
230         }
231     }
232 
233     if (igCollapsingHeader("Widgets"))
234     {
235 
236         if (igTreeNode("Basic"))
237         {
238             static int clicked = 0;
239             if (igButton("Button")) 
240                 clicked++;
241             if (clicked & 1)
242             {
243                 igSameLine();
244                 igText("Thanks for clicking me!");
245             }
246 
247             static bool check = true;
248             igCheckbox("checkbox", &check);
249 
250             static int e = 0;
251             igRadioButton("radio a", &e, 0); igSameLine();
252             igRadioButton("radio b", &e, 1); igSameLine();
253             igRadioButton("radio c", &e, 2);
254 
255             // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
256             for (int i = 0; i < 7; i++)
257             {
258                 if (i > 0) igSameLine();
259                 igPushIDInt(i);
260                 igPushStyleColor(ImGuiCol_Button, ImColor.HSV(i/7.0f, 0.6f, 0.6f).asImVec4);
261                 igPushStyleColor(ImGuiCol_ButtonHovered, ImColor.HSV(i/7.0f, 0.7f, 0.7f).asImVec4);
262                 igPushStyleColor(ImGuiCol_ButtonActive, ImColor.HSV(i/7.0f, 0.8f, 0.8f).asImVec4);
263                 igButton("Click");
264                 igPopStyleColor(3);
265                 igPopID();
266             }
267 
268             igText("Hover over me");
269             if (igIsItemHovered())
270                 igSetTooltip("I am a tooltip");
271 
272             igSameLine();
273             igText("- or me");
274             if (igIsItemHovered())
275             {
276                 igBeginTooltip();
277                 igText("I am a fancy tooltip");
278                 static float[] arr = [ 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f ];
279                 igPlotLines("Curve", arr.ptr, cast(int)IM_ARRAYSIZE(arr));
280                 igEndTooltip();
281             }
282 
283             // Testing ImGuiOnceUponAFrame helper.
284             //static ImGuiOnceUponAFrame once;
285             //for (int i = 0; i < 5; i++)
286             //    if (once)
287             //        igText("This will be displayed only once.");
288 
289             igSeparator();
290 
291             igLabelText("label", "Value");
292 
293             static int item = 1;
294             igCombo2("combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");   // Combo using values packed in a single constant string (for really quick combo)
295 
296             const(char)*[] items = [ "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK" ];
297             static int item2 = -1;
298             igCombo("combo scroll", &item2, items.ptr, cast(int)IM_ARRAYSIZE(items));   // Combo using proper array. You can also pass a callback to retrieve array value, no need to create/copy an array just for that.
299 
300             {
301                 static char[128] str0 = "Hello, world!";
302                 static int i0=123;
303                 static float f0=0.001f;
304                 igInputText("input text", str0.ptr, IM_ARRAYSIZE(str0));
305                 igSameLine(); 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");
306 
307                 igInputInt("input int", &i0);
308                 igSameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n  e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n");
309 
310                 igInputFloat("input float", &f0, 0.01f, 1.0f);
311 
312                 static float[4] vec4a = [ 0.10f, 0.20f, 0.30f, 0.44f ];
313                 igInputFloat3("input float3", vec4a[0..3]);
314             }
315 
316             {
317                 static int i1=50, i2=42;
318                 igDragInt("drag int", &i1, 1);
319                 igSameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value.");
320 
321                 igDragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%");
322 
323                 static float f1=1.00f, f2=0.0067f;
324                 igDragFloat("drag float", &f1, 0.005f);
325                 igDragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
326             }
327 
328             {
329                 static int i3=0;
330                 igSliderInt("slider int", &i3, -1, 3);
331                 igSameLine(); ShowHelpMarker("CTRL+click to input value.");
332 
333                 static float f3=0.123f, f4=0.0f;
334                 igSliderFloat("slider float", &f3, 0.0f, 1.0f, "ratio = %.3f");
335                 igSliderFloat("slider log float", &f4, -10.0f, 10.0f, "%.4f", 3.0f);
336                 static float angle = 0.0f;
337                 igSliderAngle("slider angle", &angle);
338             }
339 
340             static float[3] col1 = [ 1.0f,0.0f,0.2f ];
341             static float[4] col2 = [ 0.4f,0.7f,0.0f,0.5f ];
342             igColorEdit3("color 1", col1);
343             igSameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n");
344 
345             igColorEdit4("color 2", col2);
346 
347             const(char)*[] listbox_items = [ "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" ];
348             static int listbox_item_current = 1;
349             igListBox("listbox\n(single select)", &listbox_item_current, listbox_items.ptr, cast(int)IM_ARRAYSIZE(listbox_items), 4);
350 
351             //static int listbox_item_current2 = 2;
352             //igPushItemWidth(-1);
353             //igListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
354             //igPopItemWidth();
355 
356             igTreePop();
357         }
358 
359         if (igTreeNode("Trees"))
360         {
361             if (igTreeNode("Basic trees"))
362             {
363                 for (int i = 0; i < 5; i++)
364                     if (igTreeNodePtr(cast(void*)cast(intptr_t)i, "Child %d", i))
365                     {
366                         igText("blah blah");
367                         igSameLine(); 
368                         if (igSmallButton("print")) printf("Child %d pressed", i);
369                         igTreePop();
370                     }
371                 igTreePop();
372             }
373 
374             if (igTreeNode("Advanced, with Selectable nodes"))
375             {
376                 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.");
377                 static bool align_label_with_current_x_position = false;
378                 igCheckbox("Align label with current X position)", &align_label_with_current_x_position);
379                 igText("Hello!");
380                 if (align_label_with_current_x_position)
381                     igUnindent(igGetTreeNodeToLabelSpacing());
382 
383                 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.
384                 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.
385                 igPushStyleVar(ImGuiStyleVar_IndentSpacing, igGetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents.
386                 for (int i = 0; i < 6; i++)
387                 {
388                     // Disable the default open on single-click behavior and pass in Selected flag according to our selection state.
389                     ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0);
390                     if (i < 3)
391                     {
392                         // Node
393                         bool node_open = igTreeNodeExPtr(cast(void*)cast(intptr_t)i, node_flags, "Selectable Node %d", i);
394                         if (igIsItemClicked()) 
395                             node_clicked = i;
396                         if (node_open)
397                         {
398                             igText("Blah blah\nBlah Blah");
399                             igTreePop();
400                         }
401                     }
402                     else
403                     {
404                         // 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().
405                         igTreeNodeExPtr(cast(void*)cast(intptr_t)i, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen, "Selectable Leaf %d", i);
406                         if (igIsItemClicked()) 
407                             node_clicked = i;
408                     }
409                 }
410                 if (node_clicked != -1)
411                 {
412                     // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.
413                     if (igGetIO().KeyCtrl)
414                         selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
415                     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
416                         selection_mask = (1 << node_clicked);           // Click to single-select
417                 }
418                 igPopStyleVar();
419                 if (align_label_with_current_x_position)
420                     igIndent(igGetTreeNodeToLabelSpacing());
421                 igTreePop();
422             }
423             igTreePop();
424         }
425 
426         if (igTreeNode("Collapsing Headers"))
427         {
428             static bool closable_group = true;
429             igCheckbox("Enable extra group", &closable_group);
430             if (igCollapsingHeader("Header"))
431             {
432                 igText("IsItemHovered: %d", igIsItemHovered());
433                 for (int i = 0; i < 5; i++)
434                     igText("Some content %d", i);
435             }
436             if (igCollapsingHeaderEx("Header with a close button", &closable_group))
437             {
438                 igText("IsItemHovered: %d", igIsItemHovered());
439                 for (int i = 0; i < 5; i++)
440                     igText("More content %d", i);
441             }
442             igTreePop();
443         }
444 
445         if (igTreeNode("Bullets"))
446         {
447             igBulletText("Bullet point 1");
448             igBulletText("Bullet point 2\nOn multiple lines");
449             igBullet(); igText("Bullet point 3 (two calls)");
450             igBullet(); igSmallButton("Button");
451             igTreePop();
452         }
453 
454         if (igTreeNode("Text"))
455         {
456             if (igTreeNode("Colored Text"))
457             {
458                 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
459                 igTextColored(ImVec4(1.0f,0.0f,1.0f,1.0f), "Pink");
460                 igTextColored(ImVec4(1.0f,1.0f,0.0f,1.0f), "Yellow");
461                 igTextDisabled("Disabled");
462                 igSameLine(); ShowHelpMarker("The TextDisabled color is stored in ImGuiStyle.");
463                 igTreePop();
464             }
465 
466             if (igTreeNode("Word Wrapping"))
467             {
468                 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
469                 igTextWrapped("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.");
470                 igSpacing();
471 
472                 static float wrap_width = 200.0f;
473                 igSliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
474 
475                 igText("Test paragraph 1:");
476                 ImVec2 pos;
477                 igGetCursorScreenPos(&pos);
478                 igGetWindowDrawList().ImDrawList_AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + igGetTextLineHeight()), IM_COL32(255,0,255,255));
479                 ImVec2 pos2;
480                 igGetCursorPos(&pos2);
481                 igPushTextWrapPos(pos2.x + wrap_width);
482                 igText("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);
483                 ImVec2 pos3;
484                 igGetItemRectMin(&pos3);
485                 ImVec2 pos4;
486                 igGetItemRectMax(&pos4);
487                 igGetWindowDrawList().ImDrawList_AddRect(pos3, pos4, IM_COL32(255,255,0,255));
488                 igPopTextWrapPos();
489 
490                 igText("Test paragraph 2:");
491                 igGetCursorScreenPos(&pos);
492                 igGetWindowDrawList().ImDrawList_AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + igGetTextLineHeight()), IM_COL32(255,0,255,255));
493                 igGetCursorPos(&pos2);
494                 igPushTextWrapPos(pos2.x + wrap_width);
495                 igText("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee   ffffffff. gggggggg!hhhhhhhh");
496                 igGetItemRectMin(&pos3);
497                 igGetItemRectMax(&pos4);
498                 igGetWindowDrawList().ImDrawList_AddRect(pos3, pos4, IM_COL32(255,255,0,255));
499                 igPopTextWrapPos();
500 
501                 igTreePop();
502             }
503 
504             if (igTreeNode("UTF-8 Text"))
505             {
506                 // UTF-8 test with Japanese characters
507                 // (needs a suitable font, try Arial Unicode or M+ fonts http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html)
508                 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
509                 // - 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')
510                 // - HOWEVER, FOR THIS DEMO FILE, BECAUSE WE WANT TO SUPPORT COMPILER, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE.
511                 //   Instead we are encoding a few string with hexadecimal constants. Don't do this in your application!
512                 // 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.
513                 igTextWrapped("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.");
514                 igText("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
515                 igText("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
516                 static char[32] buf = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; // "nihongo"
517                 igInputText("UTF-8 input", buf.ptr, IM_ARRAYSIZE(buf));
518                 igTreePop();
519             }
520             igTreePop();
521         }
522 
523         if (igTreeNode("Images"))
524         {
525             igTextWrapped("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!");
526             ImVec2 tex_screen_pos;
527             igGetCursorScreenPos(&tex_screen_pos);
528             float tex_w = cast(float)igGetIO().Fonts.ImFontAtlas_GetTexWidth;
529             float tex_h = cast(float)igGetIO().Fonts.ImFontAtlas_GetTexHeight;
530             ImTextureID tex_id = igGetIO().Fonts.ImFontAtlas_GetTexID;
531             igText("%.0fx%.0f", tex_w, tex_h);
532             igImage(tex_id, ImVec2(tex_w, tex_h), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128));
533             if (igIsItemHovered())
534             {
535                 igBeginTooltip();
536                 float focus_sz = 32.0f;
537                 ImVec2 pos;
538                 igGetMousePos(&pos);
539                 float focus_x = pos.x - tex_screen_pos.x - focus_sz * 0.5f; if (focus_x < 0.0f) focus_x = 0.0f; else if (focus_x > tex_w - focus_sz) focus_x = tex_w - focus_sz;
540                 float focus_y = pos.y - tex_screen_pos.y - focus_sz * 0.5f; if (focus_y < 0.0f) focus_y = 0.0f; else if (focus_y > tex_h - focus_sz) focus_y = tex_h - focus_sz;
541                 igText("Min: (%.2f, %.2f)", focus_x, focus_y);
542                 igText("Max: (%.2f, %.2f)", focus_x + focus_sz, focus_y + focus_sz);
543                 ImVec2 uv0 = ImVec2((focus_x) / tex_w, (focus_y) / tex_h);
544                 ImVec2 uv1 = ImVec2((focus_x + focus_sz) / tex_w, (focus_y + focus_sz) / tex_h);
545                 igImage(tex_id, ImVec2(128,128), uv0, uv1, ImColor(255,255,255,255), ImColor(255,255,255,128));
546                 igEndTooltip();
547             }
548             igTextWrapped("And now some textured buttons..");
549             static int pressed_count = 0;
550             for (int i = 0; i < 8; i++)
551             {
552                 igPushIDInt(i);
553                 int frame_padding = -1 + i;     // -1 = uses default padding
554                 if (igImageButton(tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/tex_w,32/tex_h), frame_padding, ImColor(0,0,0,255)))
555                     pressed_count += 1;
556                 igPopID();
557                 igSameLine();
558             }
559             igNewLine();
560             igText("Pressed %d times.", pressed_count);
561             igTreePop();
562         }
563 
564         if (igTreeNode("Selectables"))
565         {
566             if (igTreeNode("Basic"))
567             {
568                 static bool[4] selected = [ false, true, false, false ];
569                 igSelectableEx("1. I am selectable", &selected[0]);
570                 igSelectableEx("2. I am selectable", &selected[1]);
571                 igText("3. I am not selectable");
572                 igSelectableEx("4. I am selectable", &selected[2]);
573                 if (igSelectable("5. I am double clickable", selected[3], ImGuiSelectableFlags_AllowDoubleClick))
574                     if (igIsMouseDoubleClicked(0))
575                         selected[3] = !selected[3];
576                 igTreePop();
577             }
578             if (igTreeNode("Rendering more text into the same block"))
579             {
580                 static bool[3] selected2 = [ false, false, false ];
581                 igSelectableEx("main.c", &selected2[0]);    igSameLine(300); igText(" 2,345 bytes");
582                 igSelectableEx("Hello.cpp", &selected2[1]); igSameLine(300); igText("12,345 bytes");
583                 igSelectableEx("Hello.h", &selected2[2]);   igSameLine(300); igText(" 2,345 bytes");
584                 igTreePop();
585             }
586             if (igTreeNode("In columns"))
587             {
588                 igColumns(3, null, false);
589                 static bool[16] selected3 = 0;
590                 for (int i = 0; i < 16; i++)
591                 {
592                     char[32] label; sprintf(label.ptr, "Item %d", i);
593                     if (igSelectableEx(label.ptr, &selected3[i])) {}
594                     igNextColumn();
595                 }
596                 igColumns(1);
597                 igTreePop();
598             }
599             if (igTreeNode("Grid"))
600             {
601                 static bool[16] selected4 = [ true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true ];
602                 for (int i = 0; i < 16; i++)
603                 {
604                     igPushIDInt(i);
605                     if (igSelectableEx("Sailor", &selected4[i], 0, ImVec2(50,50)))
606                     {
607                         int x = i % 4, y = i / 4;
608                         if (x > 0) selected4[i - 1] ^= 1;
609                         if (x < 3) selected4[i + 1] ^= 1;
610                         if (y > 0) selected4[i - 4] ^= 1;
611                         if (y < 3) selected4[i + 4] ^= 1;
612                     }
613                     if ((i % 4) < 3) igSameLine();
614                     igPopID();
615                 }
616                 igTreePop();
617             }
618             igTreePop();
619         }
620 
621         if (igTreeNode("Filtered Text Input"))
622         {
623             static char[64] buf1 = ""; igInputText("default", buf1.ptr, 64);
624             static char[64] buf2 = ""; igInputText("decimal", buf2.ptr, 64, ImGuiInputTextFlags_CharsDecimal);
625             static char[64] buf3 = ""; igInputText("hexadecimal", buf3.ptr, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
626             static char[64] buf4 = ""; igInputText("uppercase", buf4.ptr, 64, ImGuiInputTextFlags_CharsUppercase);
627             static char[64] buf5 = ""; igInputText("no blank", buf5.ptr, 64, ImGuiInputTextFlags_CharsNoBlank);
628             struct TextFilters {
629                 extern(C) nothrow static int FilterImGuiLetters(ImGuiTextEditCallbackData* data) {
630                     if (data.EventChar < 256 && strchr("imgui", cast(char)data.EventChar))
631                         return 0;
632                     return 1; 
633                 } 
634             }
635             static char[64] buf6 = ""; igInputText("\"imgui\" letters", buf6.ptr, 64, ImGuiInputTextFlags_CallbackCharFilter, &TextFilters.FilterImGuiLetters);
636 
637             igText("Password input");
638             static char[64] bufpass = "password123";
639             igInputText("password", bufpass.ptr, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank);
640             igSameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
641             igInputText("password (clear)", bufpass.ptr, 64, ImGuiInputTextFlags_CharsNoBlank);
642 
643             igTreePop();
644         }
645 
646         if (igTreeNode("Multi-line Text Input"))
647         {
648             static bool read_only = false;
649             static char[1024*16] text =
650                 "/*\n" ~
651                 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" ~
652                 " the hexadecimal encoding of one offending instruction,\n" ~
653                 " more formally, the invalid operand with locked CMPXCHG8B\n" ~
654                 " instruction bug, is a design flaw in the majority of\n" ~
655                 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" ~
656                 " processors (all in the P5 microarchitecture).\n" ~
657                 "*/\n\n" ~
658                 "label:\n" ~
659                 "\tlock cmpxchg8b eax\n";
660 
661             igPushStyleVarVec(ImGuiStyleVar_FramePadding, ImVec2(0,0));
662             igCheckbox("Read-only", &read_only);
663             igPopStyleVar();
664             igInputTextMultiline("##source", text.ptr, IM_ARRAYSIZE(text), ImVec2(-1.0f, igGetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0));
665             igTreePop();
666         }
667 
668 
669         if (igTreeNode("Plots widgets"))
670         {
671             static bool animate = true;
672             igCheckbox("Animate", &animate);
673 
674             static float[] arr2 = [ 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f ];
675             igPlotLines("Frame Times", arr2.ptr, cast(int)IM_ARRAYSIZE(arr2));
676 
677             // Create a dummy array of contiguous float values to plot
678             // 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.
679             static float[90] values = 0;
680             static int values_offset = 0;
681             static float refresh_time = 0.0f;
682             if (!animate || refresh_time == 0.0f)
683                 refresh_time = igGetTime();
684             while (refresh_time < igGetTime()) // Create dummy data at fixed 60 hz rate for the demo
685             {
686                 static float phase = 0.0f;
687                 values[values_offset] = cosf(phase);
688                 values_offset = (values_offset+1) % cast(int)IM_ARRAYSIZE(values);
689                 phase += 0.10f*values_offset;
690                 refresh_time += 1.0f/60.0f;
691             }
692             igPlotLines("Lines", values.ptr, cast(int)IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80));
693             igPlotHistogram("Histogram", arr2.ptr, cast(int)IM_ARRAYSIZE(arr2), 0, null, 0.0f, 1.0f, ImVec2(0,80));
694 
695             // Use functions to generate output
696             // 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.
697             extern (C) nothrow struct Funcs
698             {
699                 static float Sin(void*, int i) { return sinf(i * 0.1f); }
700                 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
701             }
702             static int func_type = 0, display_count = 70;
703             igSeparator();
704             igPushItemWidth(100); igCombo2("func", &func_type, "Sin\0Saw\0"); igPopItemWidth();
705             igSameLine();
706             igSliderInt("Sample count", &display_count, 1, 400);
707             auto func = (func_type == 0) ? &Funcs.Sin : &Funcs.Saw;
708             igPlotLines2("Lines", func, null, display_count, 0, null, -1.0f, 1.0f, ImVec2(0,80));
709             igPlotHistogram2("Histogram", func, null, display_count, 0, null, -1.0f, 1.0f, ImVec2(0,80));
710             igSeparator();
711 
712             // Animate a simple progress bar
713             static float progress = 0.0f, progress_dir = 1.0f;
714             if (animate)
715             {
716                 progress += progress_dir * 0.4f * igGetIO().DeltaTime;
717                 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
718                 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
719             }
720 
721             // 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.
722             auto size_arg = ImVec2(0.0f, 0.0f);
723             igProgressBar(progress, &size_arg);
724             igSameLine(0.0f, igGetStyle().ItemInnerSpacing.x);
725             igText("Progress Bar");
726 
727             float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress;
728             char[32] buf;
729             sprintf(buf.ptr, "%d/%d", cast(int)(progress_saturated*1753), 1753);
730             igProgressBar(progress, &size_arg, buf.ptr);
731             igTreePop();
732         }
733 
734         if (igTreeNode("Color/Picker Widgets"))
735         {
736             static ImVec4 color = ImColor(114, 144, 154, 200);
737 
738             static bool hdr = false;
739             static bool alpha_preview = true;
740             static bool alpha_half_preview = false;
741             static bool options_menu = true;
742             igCheckbox("With HDR", &hdr); igSameLine(); ShowHelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
743             igCheckbox("With Alpha Preview", &alpha_preview);
744             igCheckbox("With Half Alpha Preview", &alpha_half_preview);
745             igCheckbox("With Options Menu", &options_menu); igSameLine(); ShowHelpMarker("Right-click on the individual color widget to show options.");
746             int misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
747 
748             igText("Color widget:");
749             igSameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n");
750             igColorEdit3("MyColor##1", (&color.x)[0..3], misc_flags);
751 
752             igText("Color widget HSV with Alpha:");
753             igColorEdit4("MyColor##2", (&color.x)[0..4], ImGuiColorEditFlags_HSV | misc_flags);
754 
755             igText("Color widget with Float Display:");
756             igColorEdit4("MyColor##2f", (&color.x)[0..4], ImGuiColorEditFlags_Float | misc_flags);
757 
758             igText("Color button with Picker:");
759             igSameLine(); 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.");
760             igColorEdit4("MyColor##3", (&color.x)[0..4], ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
761 
762             igText("Color button with Custom Picker Popup:");
763             static bool saved_palette_inited = false;
764             static ImVec4[32] saved_palette;
765             static ImVec4 backup_color;
766             if (!saved_palette_inited)
767                 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
768                     igColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, &saved_palette[n].x, &saved_palette[n].y, &saved_palette[n].z);
769             bool open_popup = igColorButton("MyColor##3b", color, misc_flags);
770             igSameLine();
771             open_popup |= igButton("Palette");
772             if (open_popup)
773             {
774                 igOpenPopup("mypicker");
775                 backup_color = color;
776             }
777             if (igBeginPopup("mypicker"))
778             {
779                 // FIXME: Adding a drag and drop example here would be perfect!
780                 igText("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
781                 igSeparator();
782                 igColorPicker4("##picker", (&color.x)[0..4], misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
783                 igSameLine();
784                 igBeginGroup();
785                 igText("Current");
786                 igColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40));
787                 igText("Previous");
788                 if (igColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60,40)))
789                     color = backup_color;
790                 igSeparator();
791                 igText("Palette");
792                 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
793                 {
794                     igPushIDInt(n);
795                     if ((n % 8) != 0)
796                         igSameLine(0.0f, igGetStyle().ItemSpacing.y);
797                     if (igColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20,20)))
798                         color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
799                     igPopID();
800                 }
801                 igEndGroup();
802                 igEndPopup();
803             }
804 
805             igText("Color button only:");
806             igColorButton("MyColor##3b", color, misc_flags, ImVec2(80,80));
807 
808             igText("Color picker:");
809             static bool alpha = true;
810             static bool alpha_bar = true;
811             static bool side_preview = true;
812             static bool ref_color = false;
813             static ImVec4 ref_color_v = ImVec4(1.0f,0.0f,1.0f,0.5f);
814             static int inputs_mode = 2;
815             static int picker_mode = 0;
816             igCheckbox("With Alpha", &alpha);
817             igCheckbox("With Alpha Bar", &alpha_bar);
818             igCheckbox("With Side Preview", &side_preview);
819             if (side_preview)
820             {
821                 igSameLine();
822                 igCheckbox("With Ref Color", &ref_color);
823                 if (ref_color)
824                 {
825                     igSameLine();
826                     igColorEdit4("##RefColor", (&ref_color_v.x)[0..4], ImGuiColorEditFlags_NoInputs | misc_flags);
827                 }
828             }
829             igCombo2("Inputs Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0");
830             igCombo2("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
831             igSameLine(); ShowHelpMarker("User can right-click the picker to change mode.");
832             ImGuiColorEditFlags flags = misc_flags;
833             if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
834             if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
835             if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
836             if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
837             if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
838             if (inputs_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;
839             if (inputs_mode == 2) flags |= ImGuiColorEditFlags_RGB;
840             if (inputs_mode == 3) flags |= ImGuiColorEditFlags_HSV;
841             if (inputs_mode == 4) flags |= ImGuiColorEditFlags_HEX;
842             igColorPicker4("MyColor##4", (&color.x)[0..4], flags, ref_color ? &ref_color_v.x : null);
843 
844             igText("Programmatically set defaults/options:");
845             igSameLine(); 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.");
846             if (igButton("Uint8 + HSV"))
847                 igSetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_HSV);
848             igSameLine();
849             if (igButton("Float + HDR"))
850                 igSetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_RGB);
851 
852             igTreePop();
853         }
854 
855         if (igTreeNode("Range Widgets"))
856         {
857             static float begin = 10, end = 90;
858             static int begin_i = 100, end_i = 1000;
859             igDragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%");
860             igDragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %.0f units", "Max: %.0f units");
861             igTreePop();
862         }
863 
864         if (igTreeNode("Multi-component Widgets"))
865         {
866             static float[4] vec4f = [ 0.10f, 0.20f, 0.30f, 0.44f ];
867             static int[4] vec4i = [ 1, 5, 100, 255 ];
868 
869             igInputFloat2("input float2", vec4f[0..2]);
870             igDragFloat2("drag float2", vec4f[0..2], 0.01f, 0.0f, 1.0f);
871             igSliderFloat2("slider float2", vec4f[0..2], 0.0f, 1.0f);
872             igDragInt2("drag int2", vec4i[0..2], 1, 0, 255);
873             igInputInt2("input int2", vec4i[0..2]);
874             igSliderInt2("slider int2", vec4i[0..2], 0, 255);
875             igSpacing();
876 
877             igInputFloat3("input float3", vec4f[0..3]);
878             igDragFloat3("drag float3", vec4f[0..3], 0.01f, 0.0f, 1.0f);
879             igSliderFloat3("slider float3", vec4f[0..3], 0.0f, 1.0f);
880             igDragInt3("drag int3", vec4i[0..3], 1, 0, 255);
881             igInputInt3("input int3", vec4i[0..3]);
882             igSliderInt3("slider int3", vec4i[0..3], 0, 255);
883             igSpacing();
884 
885             igInputFloat4("input float4", vec4f);
886             igDragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
887             igSliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
888             igInputInt4("input int4", vec4i);
889             igDragInt4("drag int4", vec4i, 1, 0, 255);
890             igSliderInt4("slider int4", vec4i, 0, 255);
891 
892             igTreePop();
893         }
894 
895         if (igTreeNode("Vertical Sliders"))
896         {
897             const float spacing = 4;
898             igPushStyleVarVec(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
899 
900             static int int_value = 0;
901             igVSliderInt("##int", ImVec2(18,160), &int_value, 0, 5);
902             igSameLine();
903 
904             static float[7] values2 = [ 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f ];
905             igPushIDStr("set1");
906             for (int i = 0; i < 7; i++)
907             {
908                 if (i > 0) igSameLine();
909                 igPushIDInt(i);
910                 igPushStyleColor(ImGuiCol_FrameBg, ImColor.HSV(i/7.0f, 0.5f, 0.5f).asImVec4);
911                 igPushStyleColor(ImGuiCol_FrameBgHovered, ImColor.HSV(i/7.0f, 0.6f, 0.5f).asImVec4);
912                 igPushStyleColor(ImGuiCol_FrameBgActive, ImColor.HSV(i/7.0f, 0.7f, 0.5f).asImVec4);
913                 igPushStyleColor(ImGuiCol_SliderGrab, ImColor.HSV(i/7.0f, 0.9f, 0.9f).asImVec4);
914                 igVSliderFloat("##v", ImVec2(18,160), &values2[i], 0.0f, 1.0f, "");
915                 if (igIsItemActive() || igIsItemHovered())
916                     igSetTooltip("%.3f", values2[i]);
917                 igPopStyleColor(4);
918                 igPopID();
919             }
920             igPopID();
921 
922             igSameLine();
923             igPushIDStr("set2");
924             static float[4] values3 = [ 0.20f, 0.80f, 0.40f, 0.25f ];
925             const int rows = 3;
926             const ImVec2 small_slider_size = ImVec2(18, (160.0f-(rows-1)*spacing)/rows);
927             for (int nx = 0; nx < 4; nx++)
928             {
929                 if (nx > 0) igSameLine();
930                 igBeginGroup();
931                 for (int ny = 0; ny < rows; ny++)
932                 {
933                     igPushIDInt(nx*rows+ny);
934                     igVSliderFloat("##v", small_slider_size, &values3[nx], 0.0f, 1.0f, "");
935                     if (igIsItemActive() || igIsItemHovered())
936                         igSetTooltip("%.3f", values3[nx]);
937                     igPopID();
938                 }
939                 igEndGroup();
940             }
941             igPopID();
942 
943             igSameLine();
944             igPushIDStr("set3");
945             for (int i = 0; i < 4; i++)
946             {
947                 if (i > 0) igSameLine();
948                 igPushIDInt(i);
949                 igPushStyleVar(ImGuiStyleVar_GrabMinSize, 40);
950                 igVSliderFloat("##v", ImVec2(40,160), &values2[i], 0.0f, 1.0f, "%.2f\nsec");
951                 igPopStyleVar();
952                 igPopID();
953             }
954             igPopID();
955             igPopStyleVar();
956             igTreePop();
957         }
958     }
959 
960     if (igCollapsingHeader("Layout"))
961     {
962         if (igTreeNode("Child regions"))
963         {
964             igText("Without border");
965             static int line = 50;
966             bool goto_line = igButton("Goto");
967             igSameLine();
968             igPushItemWidth(100);
969             goto_line |= igInputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue);
970             igPopItemWidth();
971             igBeginChild("Sub1", ImVec2(igGetWindowContentRegionWidth() * 0.5f,300), false, ImGuiWindowFlags_HorizontalScrollbar);
972             for (int i = 0; i < 100; i++)
973             {
974                 igText("%04d: scrollable region", i);
975                 if (goto_line && line == i)
976                     igSetScrollHere();
977             }
978             if (goto_line && line >= 100)
979                 igSetScrollHere();
980             igEndChild();
981 
982             igSameLine();
983 
984             igPushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
985             igBeginChild("Sub2", ImVec2(0,300), true);
986             igText("With border");
987             igColumns(2);
988             for (int i = 0; i < 100; i++)
989             {
990                 if (i == 50)
991                     igNextColumn();
992                 char[32] buf;
993                 sprintf(buf.ptr, "%08x", i*5731);
994                 igButton(buf.ptr, ImVec2(-1.0f, 0.0f));
995             }
996             igEndChild();
997             igPopStyleVar();
998 
999             igTreePop();
1000         }
1001 
1002         if (igTreeNode("Widgets Width"))
1003         {
1004             static float f = 0.0f;
1005             igText("PushItemWidth(100)");
1006             igSameLine(); ShowHelpMarker("Fixed width.");
1007             igPushItemWidth(100);
1008             igDragFloat("float##1", &f);
1009             igPopItemWidth();
1010 
1011             igText("PushItemWidth(GetWindowWidth() * 0.5f)");
1012             igSameLine(); ShowHelpMarker("Half of window width.");
1013             igPushItemWidth(igGetWindowWidth() * 0.5f);
1014             igDragFloat("float##2", &f);
1015             igPopItemWidth();
1016 
1017             igText("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)");
1018             igSameLine(); ShowHelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
1019             igPushItemWidth(igGetContentRegionAvailWidth() * 0.5f);
1020             igDragFloat("float##3", &f);
1021             igPopItemWidth();
1022 
1023             igText("PushItemWidth(-100)");
1024             igSameLine(); ShowHelpMarker("Align to right edge minus 100");
1025             igPushItemWidth(-100);
1026             igDragFloat("float##4", &f);
1027             igPopItemWidth();
1028 
1029             igText("PushItemWidth(-1)");
1030             igSameLine(); ShowHelpMarker("Align to right edge");
1031             igPushItemWidth(-1);
1032             igDragFloat("float##5", &f);
1033             igPopItemWidth();
1034 
1035             igTreePop();
1036         }
1037 
1038         if (igTreeNode("Basic Horizontal Layout"))
1039         {
1040             igTextWrapped("(Use igSameLine() to keep adding items to the right of the preceding item)");
1041 
1042             // Text
1043             igText("Two items: Hello"); igSameLine();
1044             igTextColored(ImVec4(1,1,0,1), "Sailor");
1045 
1046             // Adjust spacing
1047             igText("More spacing: Hello"); igSameLine(0, 20);
1048             igTextColored(ImVec4(1,1,0,1), "Sailor");
1049 
1050             // Button
1051             igAlignTextToFramePadding();
1052             igText("Normal buttons"); igSameLine();
1053             igButton("Banana"); igSameLine();
1054             igButton("Apple"); igSameLine();
1055             igButton("Corniflower");
1056 
1057             // Button
1058             igText("Small buttons"); igSameLine();
1059             igSmallButton("Like this one"); igSameLine();
1060             igText("can fit within a text block.");
1061 
1062             // Aligned to arbitrary position. Easy/cheap column.
1063             igText("Aligned");
1064             igSameLine(150); igText("x=150");
1065             igSameLine(300); igText("x=300");
1066             igText("Aligned");
1067             igSameLine(150); igSmallButton("x=150");
1068             igSameLine(300); igSmallButton("x=300");
1069 
1070             // Checkbox
1071             static bool c1=false,c2=false,c3=false,c4=false;
1072             igCheckbox("My", &c1); igSameLine();
1073             igCheckbox("Tailor", &c2); igSameLine();
1074             igCheckbox("Is", &c3); igSameLine();
1075             igCheckbox("Rich", &c4);
1076 
1077             // Various
1078             static float f5=1.0f, f6=2.0f, f7=3.0f;
1079             igPushItemWidth(80);
1080             const(char)*[] items = [ "AAAA", "BBBB", "CCCC", "DDDD" ];
1081             static int item3 = -1;
1082             igCombo("Combo", &item3, items.ptr, cast(int)IM_ARRAYSIZE(items)); igSameLine();
1083             igSliderFloat("X", &f5, 0.0f,5.0f); igSameLine();
1084             igSliderFloat("Y", &f6, 0.0f,5.0f); igSameLine();
1085             igSliderFloat("Z", &f7, 0.0f,5.0f);
1086             igPopItemWidth();
1087 
1088             igPushItemWidth(80);
1089             igText("Lists:");
1090             static int[4] selection = [ 0, 1, 2, 3 ];
1091             for (int i = 0; i < 4; i++)
1092             {
1093                 if (i > 0) igSameLine();
1094                 igPushIDInt(i);
1095                 igListBox("", &selection[i], items.ptr, cast(int)IM_ARRAYSIZE(items));
1096                 igPopID();
1097                 //if (igIsItemHovered()) igSetTooltip("ListBox %d hovered", i);
1098             }
1099             igPopItemWidth();
1100 
1101             // Dummy
1102             ImVec2 sz = ImVec2(30,30);
1103             igButton("A", sz); igSameLine();
1104             igDummy(&sz); igSameLine();
1105             igButton("B", sz);
1106 
1107             igTreePop();
1108         }
1109 
1110         if (igTreeNode("Groups"))
1111         {
1112             igTextWrapped("(Using igBeginGroup()/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.)");
1113             igBeginGroup();
1114             {
1115                 igBeginGroup();
1116                 igButton("AAA");
1117                 igSameLine();
1118                 igButton("BBB");
1119                 igSameLine();
1120                 igBeginGroup();
1121                 igButton("CCC");
1122                 igButton("DDD");
1123                 igEndGroup();
1124                 if (igIsItemHovered())
1125                     igSetTooltip("Group hovered");
1126                 igSameLine();
1127                 igButton("EEE");
1128                 igEndGroup();
1129             }
1130             // Capture the group size and create widgets using the same size
1131             ImVec2 size;
1132             igGetItemRectSize(&size);
1133             const float[5] values = [ 0.5f, 0.20f, 0.80f, 0.60f, 0.25f ];
1134             igPlotHistogram("##values", values.ptr, cast(int)IM_ARRAYSIZE(values), 0, null, 0.0f, 1.0f, size);
1135 
1136             igButton("ACTION", ImVec2((size.x - igGetStyle().ItemSpacing.x)*0.5f,size.y));
1137             igSameLine();
1138             igButton("REACTION", ImVec2((size.x - igGetStyle().ItemSpacing.x)*0.5f,size.y));
1139             igEndGroup();
1140             igSameLine();
1141 
1142             igButton("LEVERAGE\nBUZZWORD", size);
1143             igSameLine();
1144 
1145             igListBoxHeader("List", size);
1146             igSelectable("Selected", true);
1147             igSelectable("Not Selected", false);
1148             igListBoxFooter();
1149 
1150             igTreePop();
1151         }
1152 
1153         if (igTreeNode("Text Baseline Alignment"))
1154         {
1155             igTextWrapped("(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)");
1156 
1157             igText("One\nTwo\nThree"); igSameLine();
1158             igText("Hello\nWorld"); igSameLine();
1159             igText("Banana");
1160 
1161             igText("Banana"); igSameLine();
1162             igText("Hello\nWorld"); igSameLine();
1163             igText("One\nTwo\nThree");
1164 
1165             igButton("HOP##1"); igSameLine();
1166             igText("Banana"); igSameLine();
1167             igText("Hello\nWorld"); igSameLine();
1168             igText("Banana");
1169 
1170             igButton("HOP##2"); igSameLine();
1171             igText("Hello\nWorld"); igSameLine();
1172             igText("Banana");
1173 
1174             igButton("TEST##1"); igSameLine();
1175             igText("TEST"); igSameLine();
1176             igSmallButton("TEST##2");
1177 
1178             igAlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets.
1179             igText("Text aligned to Widget"); igSameLine();
1180             igButton("Widget##1"); igSameLine();
1181             igText("Widget"); igSameLine();
1182             igSmallButton("Widget##2");
1183 
1184             // Tree
1185             const float spacing = igGetStyle().ItemInnerSpacing.x;
1186             igButton("Button##1");
1187             igSameLine(0.0f, spacing);
1188             if (igTreeNode("Node##1")) { for (int i = 0; i < 6; i++) igBulletText("Item %d..", i); igTreePop(); }    // Dummy tree data
1189 
1190             igAlignTextToFramePadding();         // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit).
1191             bool node_open = igTreeNode("Node##2");  // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content.
1192             igSameLine(0.0f, spacing); igButton("Button##2");
1193             if (node_open) { for (int i = 0; i < 6; i++) igBulletText("Item %d..", i); igTreePop(); }   // Dummy tree data
1194 
1195             // Bullet
1196             igButton("Button##3");
1197             igSameLine(0.0f, spacing);
1198             igBulletText("Bullet text");
1199 
1200             igAlignTextToFramePadding();
1201             igBulletText("Node");
1202             igSameLine(0.0f, spacing); igButton("Button##4");
1203 
1204             igTreePop();
1205         }
1206 
1207         if (igTreeNode("Scrolling"))
1208         {
1209             igTextWrapped("(Use SetScrollHere() or SetScrollFromPosY() to scroll to a given position.)");
1210             static bool track = true;
1211             static int track_line = 50, scroll_to_px = 200;
1212             igCheckbox("Track", &track);
1213             igPushItemWidth(100);
1214             igSameLine(130); track |= igDragInt("##line", &track_line, 0.25f, 0, 99, "Line = %.0f");
1215             bool scroll_to = igButton("Scroll To Pos");
1216             igSameLine(130); scroll_to |= igDragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %.0f px");
1217             igPopItemWidth();
1218             if (scroll_to) track = false;
1219 
1220             for (int i = 0; i < 5; i++)
1221             {
1222                 if (i > 0) igSameLine();
1223                 igBeginGroup();
1224                 igText("%s", (i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom").ptr);
1225                 igBeginChildEx(igGetIdPtr(cast(void*)cast(intptr_t)i), ImVec2(igGetWindowWidth() * 0.17f, 200.0f), true);
1226                 if (scroll_to) {
1227                     ImVec2 pos;
1228                     igGetCursorStartPos(&pos);
1229                     igSetScrollFromPosY(pos.y + scroll_to_px, i * 0.25f);
1230                 }
1231                 for (int line = 0; line < 100; line++)
1232                 {
1233                     if (track && line == track_line)
1234                     {
1235                         igTextColored(ImColor(255,255,0), "Line %d", line);
1236                         igSetScrollHere(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
1237                     }
1238                     else
1239                     {
1240                         igText("Line %d", line);
1241                     }
1242                 }
1243                 float scroll_y = igGetScrollY(), scroll_max_y = igGetScrollMaxY();
1244                 igEndChild();
1245                 igText("%.0f/%0.f", scroll_y, scroll_max_y);
1246                 igEndGroup();
1247             }
1248             igTreePop();
1249         }
1250 
1251         if (igTreeNode("Horizontal Scrolling"))
1252         {
1253             igBullet(); igTextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.");
1254             igBullet(); igTextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin().");
1255             static int lines = 7;
1256             igSliderInt("Lines", &lines, 1, 15);
1257             igPushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
1258             igPushStyleVarVec(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
1259             igBeginChild("scrolling", ImVec2(0, igGetFrameHeightWithSpacing()*7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar);
1260             for (int line = 0; line < lines; line++)
1261             {
1262                 // 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 
1263                 // 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)
1264                 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
1265                 for (int n = 0; n < num_buttons; n++)
1266                 {
1267                     if (n > 0) igSameLine();
1268                     igPushIDInt(n + line * 1000);
1269                     char[16] num_buf;
1270                     const(char)* label = ((!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : format("%d\0", n)).ptr;
1271                     float hue = n*0.05f;
1272                     igPushStyleColor(ImGuiCol_Button, ImColor.HSV(hue, 0.6f, 0.6f).asImVec4);
1273                     igPushStyleColor(ImGuiCol_ButtonHovered, ImColor.HSV(hue, 0.7f, 0.7f).asImVec4);
1274                     igPushStyleColor(ImGuiCol_ButtonActive, ImColor.HSV(hue, 0.8f, 0.8f).asImVec4);
1275                     igButton(label, ImVec2(40.0f + sinf(cast(float)(line + n)) * 20.0f, 0.0f));
1276                     igPopStyleColor(3);
1277                     igPopID();
1278                 }
1279             }
1280             float scroll_x = igGetScrollX(), scroll_max_x = igGetScrollMaxX();
1281             igEndChild();
1282             igPopStyleVar(2);
1283             float scroll_x_delta = 0.0f;
1284             igSmallButton("<<"); if (igIsItemActive()) scroll_x_delta = -igGetIO().DeltaTime * 1000.0f; igSameLine(); 
1285             igText("Scroll from code"); igSameLine();
1286             igSmallButton(">>"); if (igIsItemActive()) scroll_x_delta = +igGetIO().DeltaTime * 1000.0f; igSameLine(); 
1287             igText("%.0f/%.0f", scroll_x, scroll_max_x);
1288             if (scroll_x_delta != 0.0f)
1289             {
1290                 igBeginChild("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)
1291                 igSetScrollX(igGetScrollX() + scroll_x_delta);
1292                 igEnd();
1293             }
1294             igTreePop();
1295         }
1296 
1297         if (igTreeNode("Clipping"))
1298         {
1299             static ImVec2 size = ImVec2(100, 100), offset = ImVec2(50, 20);
1300             igTextWrapped("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.");
1301             igDragFloat2("size", (&size.x)[0..2], 0.5f, 0.0f, 200.0f, "%.0f");
1302             igTextWrapped("(Click and drag)");
1303             ImVec2 pos;
1304             igGetCursorScreenPos(&pos);
1305             ImVec4 clip_rect = ImVec4(pos.x, pos.y, pos.x+size.x, pos.y+size.y);
1306             igInvisibleButton("##dummy", size);
1307             if (igIsItemActive() && igIsMouseDragging()) { offset.x += igGetIO().MouseDelta.x; offset.y += igGetIO().MouseDelta.y; }
1308             igGetWindowDrawList().ImDrawList_AddRectFilled(pos, ImVec2(pos.x+size.x,pos.y+size.y), ImColor(90,90,120,255).asImU32);
1309             igGetWindowDrawList().ImDrawList_AddTextExt(igGetFont(), igGetFontSize()*2.0f, ImVec2(pos.x+offset.x,pos.y+offset.y), ImColor(255,255,255,255).asImU32, "Line 1 hello\nLine 2 clip me!", null, 0.0f, &clip_rect);
1310             igTreePop();
1311         }
1312     }
1313 
1314     if (igCollapsingHeader("Popups & Modal windows"))
1315     {
1316         if (igTreeNode("Popups"))
1317         {
1318             igTextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it.");
1319 
1320             static int selected_fish = -1;
1321             const(char)*[] names = [ "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" ];
1322             static bool[] toggles = [ true, false, false, false, false ];
1323 
1324             // Simple selection popup
1325             // (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)
1326             if (igButton("Select.."))
1327                 igOpenPopup("select");
1328             igSameLine();
1329             igText(selected_fish == -1 ? "<None>" : names[selected_fish]);
1330             if (igBeginPopup("select"))
1331             {
1332                 igText("Aquarium");
1333                 igSeparator();
1334                 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
1335                     if (igSelectable(names[i]))
1336                         selected_fish = i;
1337                 igEndPopup();
1338             }
1339 
1340             // Showing a menu with toggles
1341             if (igButton("Toggle.."))
1342                 igOpenPopup("toggle");
1343             if (igBeginPopup("toggle"))
1344             {
1345                 for (int i = 0; i < IM_ARRAYSIZE(names); i++)
1346                     igMenuItemPtr(names[i], "", &toggles[i]);
1347                 if (igBeginMenu("Sub-menu"))
1348                 {
1349                     igMenuItem("Click me");
1350                     igEndMenu();
1351                 }
1352 
1353                 igSeparator();
1354                 igText("Tooltip here");
1355                 if (igIsItemHovered())
1356                     igSetTooltip("I am a tooltip over a popup");
1357 
1358                 if (igButton("Stacked Popup"))
1359                     igOpenPopup("another popup");
1360                 if (igBeginPopup("another popup"))
1361                 {
1362                     for (int i = 0; i < IM_ARRAYSIZE(names); i++)
1363                         igMenuItemPtr(names[i], "", &toggles[i]);
1364                     if (igBeginMenu("Sub-menu"))
1365                     {
1366                         igMenuItem("Click me");
1367                         igEndMenu();
1368                     }
1369                     igEndPopup();
1370                 }
1371                 igEndPopup();
1372             }
1373 
1374             if (igButton("Popup Menu.."))
1375                 igOpenPopup("FilePopup");
1376             if (igBeginPopup("FilePopup"))
1377             {
1378                 ShowExampleMenuFile();
1379                 igEndPopup();
1380             }
1381 
1382             igTreePop();
1383         }
1384 
1385         if (igTreeNode("Context menus"))
1386         {
1387             static float value = 0.5f;
1388             igText("Value = %.3f (<-- right-click here)", value);
1389             if (igBeginPopupContextItem("item context menu"))
1390             {
1391                 if (igSelectable("Set to zero")) value = 0.0f;
1392                 if (igSelectable("Set to PI")) value = 3.1415f;
1393                 igDragFloat("Value", &value, 0.1f, 0.0f, 0.0f);
1394                 igEndPopup();
1395             }
1396 
1397             static char[32] name = "Label1";
1398             char[64] buf; sprintf(buf.ptr, "Button: %s###Button", name.ptr); // ### operator override ID ignoring the preceeding label
1399             igButton(buf.ptr);
1400             if (igBeginPopupContextItem("rename context menu"))
1401             {
1402                 igText("Edit name:");
1403                 igInputText("##edit", name.ptr, IM_ARRAYSIZE(name));
1404                 if (igButton("Close"))
1405                     igCloseCurrentPopup();
1406                 igEndPopup();
1407             }
1408             igSameLine(); igText("(<-- right-click here)");
1409 
1410             igTreePop();
1411         }
1412 
1413         if (igTreeNode("Modals"))
1414         {
1415             igTextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window.");
1416 
1417             if (igButton("Delete.."))
1418                 igOpenPopup("Delete?");
1419             if (igBeginPopupModal("Delete?", null, ImGuiWindowFlags_AlwaysAutoResize))
1420             {
1421                 igText("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
1422                 igSeparator();
1423 
1424                 //static int dummy_i = 0;
1425                 //igCombo("Combo", &dummy_i, "Delete\0Delete harder\0");
1426 
1427                 static bool dont_ask_me_next_time = false;
1428                 igPushStyleVarVec(ImGuiStyleVar_FramePadding, ImVec2(0,0));
1429                 igCheckbox("Don't ask me next time", &dont_ask_me_next_time);
1430                 igPopStyleVar();
1431 
1432                 if (igButton("OK", ImVec2(120,0))) { igCloseCurrentPopup(); }
1433                 igSameLine();
1434                 if (igButton("Cancel", ImVec2(120,0))) { igCloseCurrentPopup(); }
1435                 igEndPopup();
1436             }
1437 
1438             if (igButton("Stacked modals.."))
1439                 igOpenPopup("Stacked 1");
1440             if (igBeginPopupModal("Stacked 1"))
1441             {
1442                 igText("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDarkening] for darkening.");
1443                 static int item4 = 1;
1444                 igCombo2("Combo", &item4, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
1445 
1446                 if (igButton("Add another modal.."))
1447                     igOpenPopup("Stacked 2");
1448                 if (igBeginPopupModal("Stacked 2"))
1449                 {
1450                     igText("Hello from Stacked The Second");
1451                     if (igButton("Close"))
1452                         igCloseCurrentPopup();
1453                     igEndPopup();
1454                 }
1455 
1456                 if (igButton("Close"))
1457                     igCloseCurrentPopup();
1458                 igEndPopup();
1459             }
1460 
1461             igTreePop();
1462         }
1463 
1464         if (igTreeNode("Menus inside a regular window"))
1465         {
1466             igTextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
1467             igSeparator();
1468             // 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.
1469             // 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
1470             // 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.
1471             igPushIDStr("foo");
1472             igMenuItem("Menu item", "CTRL+M");
1473             if (igBeginMenu("Menu inside a regular window"))
1474             {
1475                 ShowExampleMenuFile();
1476                 igEndMenu();
1477             }
1478             igPopID();
1479             igSeparator();
1480             igTreePop();
1481         }
1482     }
1483 
1484     if (igCollapsingHeader("Columns"))
1485     {
1486         igPushIDStr("Columns");
1487 
1488         // Basic columns
1489         if (igTreeNode("Basic"))
1490         {
1491             igText("Without border:");
1492             igColumns(3, "mycolumns3", false);  // 3-ways, no border
1493             igSeparator();
1494             for (int n = 0; n < 14; n++)
1495             {
1496                 char[32] label;
1497                 sprintf(label.ptr, "Item %d", n);
1498                 if (igSelectable(label.ptr)) {}
1499                 //if (igButton(label, ImVec2(-1,0))) {}
1500                 igNextColumn();
1501             }
1502             igColumns(1);
1503             igSeparator();
1504 
1505             igText("With border:");
1506             igColumns(4, "mycolumns"); // 4-ways, with border
1507             igSeparator();
1508             igText("ID"); igNextColumn();
1509             igText("Name"); igNextColumn();
1510             igText("Path"); igNextColumn();
1511             igText("Flags"); igNextColumn();
1512             igSeparator();
1513             const(char)*[3] names = [ "One", "Two", "Three" ];
1514             const(char)*[3] paths = [ "/path/one", "/path/two", "/path/three" ];
1515             static int selected5 = -1;
1516             for (int i = 0; i < 3; i++)
1517             {
1518                 char[32] label;
1519                 sprintf(label.ptr, "%04d", i);
1520                 if (igSelectable(label.ptr, selected5 == i, ImGuiSelectableFlags_SpanAllColumns))
1521                     selected5 = i;
1522                 igNextColumn();
1523                 igText(names[i]); igNextColumn();
1524                 igText(paths[i]); igNextColumn();
1525                 igText("...."); igNextColumn();
1526             }
1527             igColumns(1);
1528             igSeparator();
1529             igTreePop();
1530         }
1531 
1532         // Create multiple items in a same cell before switching to next column
1533         if (igTreeNode("Mixed items"))
1534         {
1535             igColumns(3, "mixed");
1536             igSeparator();
1537 
1538             igText("Hello");
1539             igButton("Banana");
1540             igNextColumn();
1541 
1542             igText("ImGui");
1543             igButton("Apple");
1544             static float foo = 1.0f;
1545             igInputFloat("red", &foo, 0.05f, 0, 3);
1546             igText("An extra line here.");
1547             igNextColumn();
1548 
1549             igText("Sailor");
1550             igButton("Corniflower");
1551             static float bar = 1.0f;
1552             igInputFloat("blue", &bar, 0.05f, 0, 3);
1553             igNextColumn();
1554 
1555             if (igCollapsingHeader("Category A")) igText("Blah blah blah"); igNextColumn();
1556             if (igCollapsingHeader("Category B")) igText("Blah blah blah"); igNextColumn();
1557             if (igCollapsingHeader("Category C")) igText("Blah blah blah"); igNextColumn();
1558             igColumns(1);
1559             igSeparator();
1560             igTreePop();
1561         }
1562 
1563         // Word wrapping
1564         if (igTreeNode("Word-wrapping"))
1565         {
1566             igColumns(2, "word-wrapping");
1567             igSeparator();
1568             igTextWrapped("The quick brown fox jumps over the lazy dog.");
1569             igTextWrapped("Hello Left");
1570             igNextColumn();
1571             igTextWrapped("The quick brown fox jumps over the lazy dog.");
1572             igTextWrapped("Hello Right");
1573             igColumns(1);
1574             igSeparator();
1575             igTreePop();
1576         }
1577 
1578         if (igTreeNode("Borders"))
1579         {
1580             // NB: Future columns API should allow automatic horizontal borders.
1581             static bool h_borders = true;
1582             static bool v_borders = true;
1583             igCheckbox("horizontal", &h_borders);
1584             igSameLine();
1585             igCheckbox("vertical", &v_borders);
1586             igColumns(4, null, v_borders);
1587             for (int i = 0; i < 4*3; i++)
1588             {
1589                 if (h_borders && igGetColumnIndex() == 0)
1590                     igSeparator();
1591                 igText("%c%c%c", 'a'+i, 'a'+i, 'a'+i);
1592                 igText("Width %.2f\nOffset %.2f", igGetColumnWidth(), igGetColumnOffset());
1593                 igNextColumn();
1594             }
1595             igColumns(1);
1596             if (h_borders)
1597                 igSeparator();
1598             igTreePop();
1599         }
1600 
1601         // Scrolling columns
1602         /*
1603         if (igTreeNode("Vertical Scrolling"))
1604         {
1605             igBeginChild("##header", ImVec2(0, igGetTextLineHeightWithSpacing()+igGetStyle().ItemSpacing.y));
1606             igColumns(3);
1607             igText("ID"); igNextColumn();
1608             igText("Name"); igNextColumn();
1609             igText("Path"); igNextColumn();
1610             igColumns(1);
1611             igSeparator();
1612             igEndChild();
1613             igBeginChild("##scrollingregion", ImVec2(0, 60));
1614             igColumns(3);
1615             for (int i = 0; i < 10; i++)
1616             {
1617                 igText("%04d", i); igNextColumn();
1618                 igText("Foobar"); igNextColumn();
1619                 igText("/path/foobar/%04d/", i); igNextColumn();
1620             }
1621             igColumns(1);
1622             igEndChild();
1623             igTreePop();
1624         }
1625         */
1626 
1627         if (igTreeNode("Horizontal Scrolling"))
1628         {
1629             igSetNextWindowContentSize(ImVec2(1500, .0f));
1630             igBeginChild("##ScrollingRegion", ImVec2(0, igGetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar);
1631             igColumns(10);
1632             int ITEMS_COUNT = 2000;
1633             ImGuiListClipper clipper = ImGuiListClipper(ITEMS_COUNT);  // Also demonstrate using the clipper for large list
1634             while (clipper.Step())
1635             {
1636                 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
1637                     for (int j = 0; j < 10; j++)
1638                     {
1639                         igText("Line %d Column %d...", i, j);
1640                         igNextColumn();
1641                     }
1642             }
1643             igColumns(1);
1644             igEndChild();
1645             igTreePop();
1646         }
1647 
1648         bool node_open = igTreeNode("Tree within single cell");
1649         igSameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell. There's no storage of state per-cell.");
1650         if (node_open)
1651         {
1652             igColumns(2, "tree items");
1653             igSeparator();
1654             if (igTreeNode("Hello")) { igBulletText("Sailor"); igTreePop(); } igNextColumn();
1655             if (igTreeNode("Bonjour")) { igBulletText("Marin"); igTreePop(); } igNextColumn();
1656             igColumns(1);
1657             igSeparator();
1658             igTreePop();
1659         }
1660         igPopID();
1661     }
1662 
1663     if (igCollapsingHeader("Filtering"))
1664     {
1665         static ImGuiTextFilterWrapper filter;
1666         igText("Filter usage:\n" ~
1667                     "  \"\"         display all lines\n" ~
1668                     "  \"xxx\"      display lines containing \"xxx\"\n" ~
1669                     "  \"xxx,yyy\"  display lines containing \"xxx\" or \"yyy\"\n" ~
1670                     "  \"-xxx\"     hide lines containing \"xxx\"");
1671         filter.Draw();
1672         const(char)*[] lines = [ "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" ];
1673         for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
1674             if (filter.PassFilter(lines[i]))
1675                 igBulletText("%s", lines[i]);
1676     }
1677 
1678     if (igCollapsingHeader("Inputs & Focus"))
1679     {
1680         auto io = igGetIO();
1681         igCheckbox("io.MouseDrawCursor", &io.MouseDrawCursor);
1682         igSameLine(); ShowHelpMarker("Request ImGui to render a mouse cursor for you in software. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
1683 
1684         igText("WantCaptureMouse: %d", io.WantCaptureMouse);
1685         igText("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
1686         igText("WantTextInput: %d", io.WantTextInput);
1687         igText("WantMoveMouse: %d", io.WantMoveMouse);
1688 
1689         if (igTreeNode("Keyboard & Mouse State"))
1690         {
1691             if (igIsMousePosValid())
1692                 igText("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
1693             else
1694                 igText("Mouse pos: <INVALID>");
1695             igText("Mouse down:");     for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f)   { igSameLine(); igText("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
1696             igText("Mouse clicked:");  for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (igIsMouseClicked(i))          { igSameLine(); igText("b%d", i); }
1697             igText("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (igIsMouseDoubleClicked(i)) { igSameLine(); igText("b%d", i); }
1698             igText("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (igIsMouseReleased(i))         { igSameLine(); igText("b%d", i); }
1699             igText("Mouse wheel: %.1f", io.MouseWheel);
1700 
1701             igText("Keys down:");      for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f)     { igSameLine(); igText("%d (%.02f secs)", i, io.KeysDownDuration[i]); }
1702             igText("Keys pressed:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (igIsKeyPressed(i))             { igSameLine(); igText("%d", i); }
1703             igText("Keys release:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (igIsKeyReleased(i))            { igSameLine(); igText("%d", i); }
1704             igText("Keys mods: %s%s%s%s", (io.KeyCtrl ? "CTRL " : "").ptr, (io.KeyShift ? "SHIFT " : "").ptr, (io.KeyAlt ? "ALT " : "").ptr, (io.KeySuper ? "SUPER " : "").ptr);
1705 
1706 
1707             igButton("Hovering me sets the\nkeyboard capture flag");
1708             if (igIsItemHovered())
1709                 igCaptureKeyboardFromApp(true);
1710             igSameLine();
1711             igButton("Holding me clears the\nthe keyboard capture flag");
1712             if (igIsItemActive())
1713                 igCaptureKeyboardFromApp(false);
1714 
1715             igTreePop();
1716         }
1717 
1718         if (igTreeNode("Tabbing"))
1719         {
1720             igText("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
1721             static char[32] buf7 = "dummy";
1722             igInputText("1", buf7.ptr, IM_ARRAYSIZE(buf7));
1723             igInputText("2", buf7.ptr, IM_ARRAYSIZE(buf7));
1724             igInputText("3", buf7.ptr, IM_ARRAYSIZE(buf7));
1725             igPushAllowKeyboardFocus(false);
1726             igInputText("4 (tab skip)", buf7.ptr, IM_ARRAYSIZE(buf7));
1727             //igSameLine(); ShowHelperMarker("Use igPushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets.");
1728             igPopAllowKeyboardFocus();
1729             igInputText("5", buf7.ptr, IM_ARRAYSIZE(buf7));
1730             igTreePop();
1731         }
1732 
1733         if (igTreeNode("Focus from code"))
1734         {
1735             bool focus_1 = igButton("Focus on 1"); igSameLine();
1736             bool focus_2 = igButton("Focus on 2"); igSameLine();
1737             bool focus_3 = igButton("Focus on 3");
1738             int has_focus = 0;
1739             static char[128] buf8 = "click on a button to set focus";
1740 
1741             if (focus_1) igSetKeyboardFocusHere();
1742             igInputText("1", buf8.ptr, IM_ARRAYSIZE(buf8));
1743             if (igIsItemActive()) has_focus = 1;
1744 
1745             if (focus_2) igSetKeyboardFocusHere();
1746             igInputText("2", buf8.ptr, IM_ARRAYSIZE(buf8));
1747             if (igIsItemActive()) has_focus = 2;
1748 
1749             igPushAllowKeyboardFocus(false);
1750             if (focus_3) igSetKeyboardFocusHere();
1751             igInputText("3 (tab skip)", buf8.ptr, IM_ARRAYSIZE(buf8));
1752             if (igIsItemActive()) has_focus = 3;
1753             igPopAllowKeyboardFocus();
1754             if (has_focus)
1755                 igText("Item with focus: %d", has_focus);
1756             else
1757                 igText("Item with focus: <none>");
1758             igTextWrapped("Cursor & selection are preserved when refocusing last used item in code.");
1759             igTreePop();
1760         }
1761 
1762         if (igTreeNode("Focused & Hovered Test"))
1763         {
1764             static bool embed_all_inside_a_child_window = false;
1765             igCheckbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window);
1766             if (embed_all_inside_a_child_window)
1767                 igBeginChild("embeddingchild", ImVec2(0, igGetFontSize() * 25), true);
1768 
1769             // Testing IsWindowFocused() function with its various flags (note that the flags can be combined)
1770             igBulletText(
1771                 "IsWindowFocused() = %d\n" ~
1772                 "IsWindowFocused(_ChildWindows) = %d\n" ~
1773                 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" ~
1774                 "IsWindowFocused(_RootWindow) = %d\n",
1775                 igIsWindowFocused(),
1776                 igIsWindowFocused(ImGuiHoveredFlags_ChildWindows),
1777                 igIsWindowFocused(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
1778                 igIsWindowFocused(ImGuiHoveredFlags_RootWindow));
1779 
1780             // Testing IsWindowHovered() function with its various flags (note that the flags can be combined)
1781             igBulletText(
1782                 "IsWindowHovered() = %d\n" ~
1783                 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" ~
1784                 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" ~
1785                 "IsWindowHovered(_ChildWindows) = %d\n" ~
1786                 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" ~
1787                 "IsWindowHovered(_RootWindow) = %d\n",
1788                 igIsWindowHovered(),
1789                 igIsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
1790                 igIsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
1791                 igIsWindowHovered(ImGuiHoveredFlags_ChildWindows),
1792                 igIsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
1793                 igIsWindowHovered(ImGuiHoveredFlags_RootWindow));
1794 
1795             // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code)
1796             igButton("ITEM");
1797             igBulletText(
1798                 "IsItemHovered() = %d\n" ~
1799                 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" ~
1800                 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" ~
1801                 "IsItemHovered(_AllowWhenOverlapped) = %d\n" ~
1802                 "IsItemhovered(_RectOnly) = %d\n",
1803                 igIsItemHovered(),
1804                 igIsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
1805                 igIsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
1806                 igIsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped),
1807                 igIsItemHovered(ImGuiHoveredFlags_RectOnly));
1808 
1809             igBeginChild("child", ImVec2(0,50), true);
1810             igText("This is another child window for testing IsWindowHovered() flags.");
1811             igEndChild();
1812 
1813             if (embed_all_inside_a_child_window)
1814                 igEndChild();
1815 
1816             igTreePop();
1817         }
1818 
1819         if (igTreeNode("Dragging"))
1820         {
1821             igTextWrapped("You can use igGetMouseDragDelta(0) to query for the dragged amount on any widget.");
1822             for (int button = 0; button < 3; button++)
1823                 igText("IsMouseDragging(%d):\n  w/ default threshold: %d,\n  w/ zero threshold: %d\n  w/ large threshold: %d", 
1824                     button, igIsMouseDragging(button), igIsMouseDragging(button, 0.0f), igIsMouseDragging(button, 20.0f));
1825             igButton("Drag Me");
1826             if (igIsItemActive())
1827             {
1828                 // Draw a line between the button and the mouse cursor
1829                 ImDrawList* draw_list = igGetWindowDrawList();
1830                 draw_list.ImDrawList_PushClipRectFullScreen();
1831                 ImVec2 pos1;
1832                 igCalcItemRectClosestPoint(&pos1, igGetIO().MousePos, true, -2.0f);
1833                 draw_list.ImDrawList_AddLine(pos1, io.MousePos, ImColor(igGetStyle().Colors[ImGuiCol_Button]).asImU32, 4.0f);
1834                 draw_list.ImDrawList_PopClipRect();
1835 
1836                 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold)
1837                 // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta()
1838                 ImVec2 value_raw;
1839                 igGetMouseDragDelta(&value_raw, 0, 0.0f);
1840                 ImVec2 value_with_lock_threshold;
1841                 igGetMouseDragDelta(&value_with_lock_threshold, 0);
1842                 ImVec2 mouse_delta = io.MouseDelta;
1843                 igSameLine(); igText("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);
1844             }
1845             igTreePop();
1846         }
1847 
1848         if (igTreeNode("Mouse cursors"))
1849         {
1850             const string[] mouse_cursors_names = [ "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE" ];
1851             assert(mouse_cursors_names.length == ImGuiMouseCursor_Count_);
1852 
1853             igText("Current mouse cursor = %d: %s", igGetMouseCursor(), toStringz(mouse_cursors_names[igGetMouseCursor()]));
1854             igText("Hover to see mouse cursors:");
1855             igSameLine(); ShowHelpMarker("Your application can render a different mouse cursor based on what igGetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it.");
1856             for (int i = 0; i < ImGuiMouseCursor_Count_; i++)
1857             {
1858                 auto label = format!"Mouse cursor %d: %s"(i, mouse_cursors_names[i]);
1859                 igBullet(); igSelectable(toStringz(label), false);
1860                 if (igIsItemHovered())
1861                     igSetMouseCursor(i);
1862             }
1863             igTreePop();
1864         }
1865     }
1866 
1867     igEnd();
1868 }
1869 
1870 void igShowStyleEditor(ImGuiStyle* ref_ = null)
1871 {
1872     ImGuiStyle* style = igGetStyle();
1873 
1874     // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to the default style)
1875     static ImGuiStyle ref_saved_style;
1876 
1877     // Default to using internal storage as reference
1878     static bool init = true;
1879     if (init && ref_ == null)
1880         ref_saved_style = *style;
1881     init = false;
1882     if (ref_ == null)
1883         ref_ = &ref_saved_style;
1884 
1885     igPushItemWidth(igGetWindowWidth() * 0.50f);
1886 
1887     if (igShowStyleSelector("Colors##Selector"))
1888         ref_saved_style = *style;
1889     igShowFontSelector("Fonts##Selector");
1890 
1891     // Simplified Settings
1892     if (igSliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) 
1893         style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
1894     { bool window_border = (style.WindowBorderSize > 0.0f); if (igCheckbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; }
1895     igSameLine();
1896     { bool frame_border = (style.FrameBorderSize > 0.0f); if (igCheckbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; }
1897     igSameLine();
1898     { bool popup_border = (style.PopupBorderSize > 0.0f); if (igCheckbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; }
1899 
1900     // Save/Revert button
1901     if (igButton("Save Ref"))
1902         *ref_ = ref_saved_style = *style;
1903     igSameLine();
1904     if (igButton("Revert Ref"))
1905         *style = *ref_;
1906     igSameLine();
1907     ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere.");
1908 
1909     if (igTreeNode("Rendering"))
1910     {
1911         igCheckbox("Anti-aliased lines", &style.AntiAliasedLines); igSameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
1912         igCheckbox("Anti-aliased fill", &style.AntiAliasedFill);
1913         igPushItemWidth(100);
1914         igDragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, null, 2.0f);
1915         if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f;
1916         igDragFloat("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.
1917         igPopItemWidth();
1918         igTreePop();
1919     }
1920 
1921     if (igTreeNode("Settings"))
1922     {
1923         igSliderFloat2("WindowPadding", (&style.WindowPadding.x)[0..2], 0.0f, 20.0f, "%.0f");
1924         igSliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f");
1925         igSliderFloat2("FramePadding", (&style.FramePadding.x)[0..2], 0.0f, 20.0f, "%.0f");
1926         igSliderFloat2("ItemSpacing", (&style.ItemSpacing.x)[0..2], 0.0f, 20.0f, "%.0f");
1927         igSliderFloat2("ItemInnerSpacing", (&style.ItemInnerSpacing.x)[0..2], 0.0f, 20.0f, "%.0f");
1928         igSliderFloat2("TouchExtraPadding",(&style.TouchExtraPadding.x)[0..2], 0.0f, 10.0f, "%.0f");
1929         igSliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
1930         igSliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
1931         igSliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
1932         igText("BorderSize");
1933         igSliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
1934         igSliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
1935         igSliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
1936         igSliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
1937         igText("Rounding");
1938         igSliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f");
1939         igSliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f");
1940         igSliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
1941         igSliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
1942         igSliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
1943         igText("Alignment");
1944         igSliderFloat2("WindowTitleAlign", (&style.WindowTitleAlign.x)[0..2], 0.0f, 1.0f, "%.2f");
1945         igSliderFloat2("ButtonTextAlign", (&style.ButtonTextAlign.x)[0..2], 0.0f, 1.0f, "%.2f"); igSameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content.");
1946         igTreePop();
1947     }
1948 
1949     if (igTreeNode("Colors"))
1950     {
1951         static int output_dest = 0;
1952         static bool output_only_modified = true;
1953         if (igButton("Export Unsaved"))
1954         {
1955             if (output_dest == 0)
1956                 igLogToClipboard();
1957             else
1958                 igLogToTTY();
1959             igLogText("ImVec4* colors = igGetStyle().Colors;" ~ IM_NEWLINE);
1960             for (int i = 0; i < ImGuiCol_COUNT; i++)
1961             {
1962                 const ImVec4 *col = &style.Colors[i];
1963                 const char* name = igGetStyleColorName(i);
1964                 if (!output_only_modified || memcmp(cast(void*)col, cast(void*)&ref_.Colors[i], ImVec4.sizeof) != 0)
1965                     igLogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" ~ IM_NEWLINE, name, 23-strlen(name), "".ptr, col.x, col.y, col.z, col.w);
1966             }
1967             igLogFinish();
1968         }
1969         igSameLine(); igPushItemWidth(120); igCombo2("##output_type", &output_dest, "To Clipboard\0To TTY\0"); igPopItemWidth();
1970         igSameLine(); igCheckbox("Only Modified Colors", &output_only_modified);
1971 
1972         igText("Tip: Left-click on colored square to open color picker,\nRight-click to open edit options menu.");
1973 
1974         static ImGuiTextFilterWrapper filter;
1975         filter.Draw("Filter colors", 200);
1976 
1977         static ImGuiColorEditFlags alpha_flags = 0;
1978         igRadioButton("Opaque", &alpha_flags, 0); igSameLine(); 
1979         igRadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); igSameLine(); 
1980         igRadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
1981 
1982         igBeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
1983         igPushItemWidth(-160);
1984         for (int i = 0; i < ImGuiCol_COUNT; i++)
1985         {
1986             const char* name = igGetStyleColorName(i);
1987             if (!filter.PassFilter(name))
1988                 continue;
1989             igPushIDInt(i);
1990             igColorEdit4("##color", (&style.Colors[i].x)[0..4], ImGuiColorEditFlags_AlphaBar | alpha_flags);
1991             if (memcmp(cast(void*)&style.Colors[i], cast(void*)&ref_.Colors[i], ImVec4.sizeof) != 0)
1992             {
1993                 // 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.
1994                 // Read the FAQ and extra_fonts/README.txt about using icon fonts. It's really easy and super convenient!
1995                 igSameLine(0.0f, style.ItemInnerSpacing.x); if (igButton("Save")) ref_.Colors[i] = style.Colors[i];
1996                 igSameLine(0.0f, style.ItemInnerSpacing.x); if (igButton("Revert")) style.Colors[i] = ref_.Colors[i];
1997             }
1998             igSameLine(0.0f, style.ItemInnerSpacing.x);
1999             igTextUnformatted(name);
2000             igPopID();
2001         }
2002         igPopItemWidth();
2003         igEndChild();
2004 
2005         igTreePop();
2006     }
2007 
2008     bool fonts_opened = igTreeNodeStr("Fonts", "Fonts (%d)", ImFontAtlas_Fonts_size(igGetIO().Fonts));
2009     if (fonts_opened)
2010     {
2011         ImFontAtlas* atlas = igGetIO().Fonts;
2012         if (igTreeNodeStr("Atlas texture", "Atlas texture (%dx%d pixels)", ImFontAtlas_GetTexWidth(atlas), ImFontAtlas_GetTexHeight(atlas)))
2013         {
2014             igImage(ImFontAtlas_GetTexID(atlas), ImVec2(ImFontAtlas_GetTexWidth(atlas), ImFontAtlas_GetTexHeight(atlas)), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128));
2015             igTreePop();
2016         }
2017         igPushItemWidth(100);
2018         for (int i = 0; i < ImFontAtlas_Fonts_size(igGetIO().Fonts); i++)
2019         {
2020             ImFont* font = ImFontAtlas_Fonts_index(atlas, i);
2021             igPushIDPtr(cast(void*)font);
2022             bool font_details_opened = igTreeNodePtr(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, ImFont_GetConfigData(font) ? &ImFont_GetConfigData(font)[0].Name[0] : "", ImFont_GetFontSize(font), ImFont_Glyphs_size(font));
2023             igSameLine(); if (igSmallButton("Set as default")) igGetIO().FontDefault = font;
2024             if (font_details_opened)
2025             {
2026                 igPushFont(font);
2027                 igText("The quick brown fox jumps over the lazy dog");
2028                 igPopFont();
2029                 float fontScale = ImFont_GetScale(font);
2030                 igDragFloat("Font scale", &fontScale, 0.005f, 0.3f, 2.0f, "%.1f");   // Scale only this font
2031                 ImFont_SetScale(font, fontScale);
2032                 igSameLine(); 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.)");
2033                 igText("Ascent: %f, Descent: %f, Height: %f", ImFont_GetAscent(font), ImFont_GetDescent(font), ImFont_GetAscent(font) - ImFont_GetDescent(font));
2034                 igText("Fallback character: '%c' (%d)", ImFont_GetFallbackChar(font), ImFont_GetFallbackChar(font));
2035                 igText("Texture surface: %d pixels (approx) ~ %dx%d", ImFont_GetMetricsTotalSurface(font), sqrtf(ImFont_GetMetricsTotalSurface(font)), sqrtf(ImFont_GetMetricsTotalSurface(font)));
2036                 for (int config_i = 0; config_i < ImFont_GetConfigDataCount(font); config_i++)
2037                 {
2038                     ImFontConfig* cfg = &ImFont_GetConfigData(font)[config_i];
2039                     igBulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg.Name.ptr, cfg.OversampleH, cfg.OversampleV, cfg.PixelSnapH);
2040                 }
2041                 if (igTreeNodeStr("Glyphs", "Glyphs (%d)", ImFont_Glyphs_size(font)))
2042                 {
2043                     // Display all glyphs of the fonts in separate pages of 256 characters
2044                     const ImFont_Glyph* glyph_fallback = ImFont_GetFallbackGlyph(font); // Forcefully/dodgily make FindGlyph() return null on fallback, which isn't the default behavior.
2045                     ImFont_SetFallbackGlyph(font, null);
2046                     for (int base = 0; base < 0x10000; base += 256)
2047                     {
2048                         int count = 0;
2049                         for (int n = 0; n < 256; n++)
2050                             count += ImFont_FindGlyph(font, cast(ImWchar)(base + n)) ? 1 : 0;
2051                         if (count > 0 && igTreeNodePtr(cast(void*)cast(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base+255, count, (count > 1 ? "glyphs" : "glyph").ptr))
2052                         {
2053                             float cell_spacing = style.ItemSpacing.y;
2054                             ImVec2 cell_size = ImVec2(ImFont_GetFontSize(font) * 1, ImFont_GetFontSize(font) * 1);
2055                             ImVec2 base_pos;
2056                             igGetCursorScreenPos(&base_pos);
2057                             ImDrawList* draw_list = igGetWindowDrawList();
2058                             for (int n = 0; n < 256; n++)
2059                             {
2060                                 ImVec2 cell_p1 = ImVec2(base_pos.x + (n % 16) * (cell_size.x + cell_spacing), base_pos.y + (n / 16) * (cell_size.y + cell_spacing));
2061                                 ImVec2 cell_p2 = ImVec2(cell_p1.x + cell_size.x, cell_p1.y + cell_size.y);
2062                                 const ImFont_Glyph* glyph = ImFont_FindGlyph(font, cast(ImWchar)(base+n));
2063                                 draw_list.ImDrawList_AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50));
2064                                 font.ImFont_RenderChar(draw_list, cell_size.x, cell_p1, igGetColorU32(ImGuiCol_Text), cast(ImWchar)(base+n)); // We use ImFont.RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string.
2065                                 if (glyph && igIsMouseHoveringRect(cell_p1, cell_p2))
2066                                 {
2067                                     igBeginTooltip();
2068                                     igText("Codepoint: U+%04X", base+n);
2069                                     igSeparator();
2070                                     igText("XAdvance: %.1f", glyph.XAdvance);
2071                                     igText("Pos: (%.2f,%.2f).(%.2f,%.2f)", glyph.X0, glyph.Y0, glyph.X1, glyph.Y1);
2072                                     igText("UV: (%.3f,%.3f).(%.3f,%.3f)", glyph.U0, glyph.V0, glyph.U1, glyph.V1);
2073                                     igEndTooltip();
2074                                 }
2075                             }
2076                             auto sz = ImVec2((cell_size.x + cell_spacing) * 16, (cell_size.y + cell_spacing) * 16);
2077                             igDummy(&sz);
2078                             igTreePop();
2079                         }
2080                     }
2081                     ImFont_SetFallbackGlyph(font, glyph_fallback);
2082                     igTreePop();
2083                 }
2084                 igTreePop();
2085             }
2086             igPopID();
2087         }
2088         static float window_scale = 1.0f;
2089         igDragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f");              // scale only this window
2090         igDragFloat("global scale", &igGetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything
2091         igPopItemWidth();
2092         igSetWindowFontScale(window_scale);
2093         igTreePop();
2094     }
2095 
2096     igPopItemWidth();
2097 }
2098 
2099 // Demonstrate creating a fullscreen menu bar and populating it.
2100 void ShowExampleAppMainMenuBar()
2101 {
2102     if (igBeginMainMenuBar())
2103     {
2104         if (igBeginMenu("File"))
2105         {
2106             ShowExampleMenuFile();
2107             igEndMenu();
2108         }
2109         if (igBeginMenu("Edit"))
2110         {
2111             if (igMenuItem("Undo", "CTRL+Z")) {}
2112             if (igMenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
2113             igSeparator();
2114             if (igMenuItem("Cut", "CTRL+X")) {}
2115             if (igMenuItem("Copy", "CTRL+C")) {}
2116             if (igMenuItem("Paste", "CTRL+V")) {}
2117             igEndMenu();
2118         }
2119         igEndMainMenuBar();
2120     }
2121 }
2122 
2123 void ShowExampleMenuFile()
2124 {
2125     igMenuItem("(dummy menu)", null, false, false);
2126     if (igMenuItem("New")) {}
2127     if (igMenuItem("Open", "Ctrl+O")) {}
2128     if (igBeginMenu("Open Recent"))
2129     {
2130         igMenuItem("fish_hat.c");
2131         igMenuItem("fish_hat.inl");
2132         igMenuItem("fish_hat.h");
2133         if (igBeginMenu("More.."))
2134         {
2135             igMenuItem("Hello");
2136             igMenuItem("Sailor");
2137             if (igBeginMenu("Recurse.."))
2138             {
2139                 ShowExampleMenuFile();
2140                 igEndMenu();
2141             }
2142             igEndMenu();
2143         }
2144         igEndMenu();
2145     }
2146     if (igMenuItem("Save", "Ctrl+S")) {}
2147     if (igMenuItem("Save As..")) {}
2148     igSeparator();
2149     if (igBeginMenu("Options"))
2150     {
2151         static bool enabled = true;
2152         igMenuItemPtr("Enabled", "", &enabled);
2153         igBeginChild("child", ImVec2(0, 60), true);
2154         for (int i = 0; i < 10; i++)
2155             igText("Scrolling Text %d", i);
2156         igEndChild();
2157         static float f = 0.5f;
2158         static int n = 0;
2159         static bool b = true;
2160         igSliderFloat("Value", &f, 0.0f, 1.0f);
2161         igInputFloat("Input", &f, 0.1f);
2162         igCombo2("Combo", &n, "Yes\0No\0Maybe\0\0");
2163         igCheckbox("Check", &b);
2164         igEndMenu();
2165     }
2166     if (igBeginMenu("Colors"))
2167     {
2168         igPushStyleVarVec(ImGuiStyleVar_FramePadding, ImVec2(0,0));
2169         for (int i = 0; i < ImGuiCol_COUNT; i++)
2170         {
2171             const char* name = igGetStyleColorName(i);
2172             ImVec4 col;
2173             igGetStyleColorVec4(&col, cast(ImGuiCol)i);
2174             igColorButton(name, col);
2175             igSameLine();
2176             igMenuItem(name);
2177         }
2178         igPopStyleVar();
2179         igEndMenu();
2180     }
2181     if (igBeginMenu("Disabled", false)) // Disabled
2182     {
2183         assert(0);
2184     }
2185     if (igMenuItem("Checked", null, true)) {}
2186     if (igMenuItem("Quit", "Alt+F4")) {}
2187 }
2188 
2189 // Demonstrate creating a window which gets auto-resized according to its content.
2190 void ShowExampleAppAutoResize(bool* p_open)
2191 {
2192     if (!igBegin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
2193     {
2194         igEnd();
2195         return;
2196     }
2197 
2198     static int lines = 10;
2199     igText("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.");
2200     igSliderInt("Number of lines", &lines, 1, 20);
2201     for (int i = 0; i < lines; i++)
2202         igText("%*sThis is line %d", i*4, "".ptr, i); // Pad with space to extend size horizontally
2203     igEnd();
2204 }
2205 
2206 // Demonstrate creating a window with custom resize constraints.
2207 void ShowExampleAppConstrainedResize(bool* p_open)
2208 {
2209     struct CustomConstraints // Helper functions to demonstrate programmatic constraints
2210     {
2211     extern (C) nothrow:
2212         static void Square(ImGuiSizeConstraintCallbackData* data) { data.DesiredSize = ImVec2(IM_MAX(data.DesiredSize.x, data.DesiredSize.y), IM_MAX(data.DesiredSize.x, data.DesiredSize.y)); }
2213         static void Step(ImGuiSizeConstraintCallbackData* data)   { float step = cast(float)cast(int)cast(intptr_t)data.UserData; data.DesiredSize = ImVec2(cast(int)(data.DesiredSize.x / step + 0.5f) * step, cast(int)(data.DesiredSize.y / step + 0.5f) * step); }
2214     }
2215 
2216     static bool auto_resize = false;
2217     static int type = 0;
2218     static int display_lines = 10;
2219     if (type == 0) igSetNextWindowSizeConstraints(ImVec2(-1, 0),    ImVec2(-1, FLT_MAX));      // Vertical only
2220     if (type == 1) igSetNextWindowSizeConstraints(ImVec2(0, -1),    ImVec2(FLT_MAX, -1));      // Horizontal only
2221     if (type == 2) igSetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
2222     if (type == 3) igSetNextWindowSizeConstraints(ImVec2(400, 0),   ImVec2(500, FLT_MAX));     // Width 300-400
2223     if (type == 4) igSetNextWindowSizeConstraints(ImVec2(-1, 400),  ImVec2(-1, 500), &CustomConstraints.Square);          // Always Square
2224     if (type == 5) igSetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), &CustomConstraints.Square);          // Always Square
2225     if (type == 6) igSetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), &CustomConstraints.Step, cast(void*)100);// Fixed Step
2226 
2227     if (igBegin("Example: Constrained Resize", p_open))
2228     {
2229         const(char)*[] desc = 
2230         [
2231             "Resize vertical only",
2232             "Resize horizontal only",
2233             "Width > 100, Height > 100",
2234             "Width 400-500",
2235             "Height 400-500",
2236             "Custom: Always Square",
2237             "Custom: Fixed Steps (100)",
2238         ];
2239         if (igButton("200x200")) { igSetWindowSize(ImVec2(200, 200)); } igSameLine();
2240         if (igButton("500x500")) { igSetWindowSize(ImVec2(500, 500)); } igSameLine();
2241         if (igButton("800x200")) { igSetWindowSize(ImVec2(800, 200)); }
2242         igPushItemWidth(200);
2243         igCombo("Constraint", &type, desc.ptr, cast(int)desc.length);
2244         igDragInt("Lines", &display_lines, 0.2f, 1, 100);
2245         igPopItemWidth();
2246         igCheckbox("Auto-resize", &auto_resize);
2247         for (int i = 0; i < display_lines; i++)
2248             igText("%*sHello, sailor! Making this line long enough for the example.", i * 4, "".ptr);
2249     }
2250     igEnd();
2251 }
2252 
2253 // Demonstrate creating a simple static window with no decoration.
2254 void ShowExampleAppFixedOverlay(bool* p_open)
2255 {
2256     const float DISTANCE = 10.0f;
2257     static int corner = 0;
2258     ImVec2 window_pos = ImVec2((corner & 1) ? igGetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? igGetIO().DisplaySize.y - DISTANCE : DISTANCE);
2259     ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
2260     igSetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
2261     igPushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.3f)); // Transparent background
2262     if (igBegin("Example: Fixed Overlay", p_open, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings))
2263     {
2264         igText("Simple overlay\nin the corner of the screen.\n(right-click to change position)");
2265         igSeparator();
2266         igText("Mouse Position: (%.1f,%.1f)", igGetIO().MousePos.x, igGetIO().MousePos.y);
2267         if (igBeginPopupContextWindow())
2268         {
2269             if (igMenuItem("Top-left", null, corner == 0)) corner = 0;
2270             if (igMenuItem("Top-right", null, corner == 1)) corner = 1;
2271             if (igMenuItem("Bottom-left", null, corner == 2)) corner = 2;
2272             if (igMenuItem("Bottom-right", null, corner == 3)) corner = 3;
2273             igEndPopup();
2274         }
2275         igEnd();
2276     }
2277     igPopStyleColor();
2278 }
2279 
2280 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation.
2281 // Read 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." about ID.
2282 void ShowExampleAppManipulatingWindowTitle(bool*)
2283 {
2284     // By default, Windows are uniquely identified by their title.
2285     // You can use the "##" and "###" markers to manipulate the display/ID.
2286 
2287     // Using "##" to display same title but have unique identifier.
2288     igSetNextWindowPos(ImVec2(100,100), ImGuiCond_FirstUseEver);
2289     igBegin("Same title as another window##1");
2290     igText("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
2291     igEnd();
2292 
2293     igSetNextWindowPos(ImVec2(100,200), ImGuiCond_FirstUseEver);
2294     igBegin("Same title as another window##2");
2295     igText("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
2296     igEnd();
2297 
2298     // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
2299     char[128] buf;
2300     sprintf(buf.ptr, "Animated title %c %d###AnimatedTitle", "|/-\\"[cast(int)(igGetTime()/0.25f)&3], rand());
2301     igSetNextWindowPos(ImVec2(100,300), ImGuiCond_FirstUseEver);
2302     igBegin(buf.ptr);
2303     igText("This window has a changing title.");
2304     igEnd();
2305 }
2306 
2307 // Demonstrate using the low-level ImDrawList to draw custom shapes. 
2308 void ShowExampleAppCustomRendering(bool* p_open)
2309 {
2310     igSetNextWindowSize(ImVec2(350,560), ImGuiCond_FirstUseEver);
2311     if (!igBegin("Example: Custom rendering", p_open))
2312     {
2313         igEnd();
2314         return;
2315     }
2316 
2317     // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc.
2318     // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4.
2319     // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types)
2320     // In this example we are not using the maths operators!
2321     ImDrawList* draw_list = igGetWindowDrawList();
2322 
2323     // Primitives
2324     igText("Primitives");
2325     static float sz = 36.0f;
2326     static ImVec4 col = ImVec4(1.0f,1.0f,0.4f,1.0f);
2327     igDragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
2328     igColorEdit3("Color", (&col.x)[0..3]);
2329     {
2330         ImVec2 p;
2331         igGetCursorScreenPos(&p);
2332         const ImU32 col32 = ImColor(col).asImU32;
2333         float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f;
2334         for (int n = 0; n < 2; n++)
2335         {
2336             float thickness = (n == 0) ? 1.0f : 4.0f;
2337             draw_list.ImDrawList_AddCircle(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 20, thickness); x += sz+spacing;
2338             draw_list.ImDrawList_AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 0.0f, ~0, thickness); x += sz+spacing;
2339             draw_list.ImDrawList_AddRect(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f, ~0, thickness); x += sz+spacing;
2340             draw_list.ImDrawList_AddTriangle(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32, thickness); x += sz+spacing;
2341             draw_list.ImDrawList_AddLine(ImVec2(x, y), ImVec2(x+sz, y   ), col32, thickness); x += sz+spacing;
2342             draw_list.ImDrawList_AddLine(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, thickness); x += sz+spacing;
2343             draw_list.ImDrawList_AddLine(ImVec2(x, y), ImVec2(x,    y+sz), col32, thickness); x += spacing;
2344             draw_list.ImDrawList_AddBezierCurve(ImVec2(x, y), ImVec2(x+sz*1.3f,y+sz*0.3f), ImVec2(x+sz-sz*1.3f,y+sz-sz*0.3f), ImVec2(x+sz, y+sz), col32, thickness);
2345             x = p.x + 4;
2346             y += sz+spacing;
2347         }
2348         draw_list.ImDrawList_AddCircleFilled(ImVec2(x+sz*0.5f, y+sz*0.5f), sz*0.5f, col32, 32); x += sz+spacing;
2349         draw_list.ImDrawList_AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32); x += sz+spacing;
2350         draw_list.ImDrawList_AddRectFilled(ImVec2(x, y), ImVec2(x+sz, y+sz), col32, 10.0f); x += sz+spacing;
2351         draw_list.ImDrawList_AddTriangleFilled(ImVec2(x+sz*0.5f, y), ImVec2(x+sz,y+sz-0.5f), ImVec2(x,y+sz-0.5f), col32); x += sz+spacing;
2352         draw_list.ImDrawList_AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x+sz, y+sz), ImColor(0,0,0).asImU32, ImColor(255,0,0).asImU32, ImColor(255,255,0).asImU32, ImColor(0,255,0).asImU32);
2353         auto sz2 = ImVec2((sz+spacing)*8, (sz+spacing)*3);
2354         igDummy(&sz2);
2355     }
2356     igSeparator();
2357     {
2358         static ImVec2[] points;
2359         static bool adding_line = false;
2360         igText("Canvas example");
2361         if (igButton("Clear")) points = null;
2362         if (points.length >= 2) { igSameLine(); if (igButton("Undo")) { points = points[0..$-2]; } }
2363         igText("Left-click and drag to add lines,\nRight-click to undo");
2364 
2365         // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered()
2366         // However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos().
2367         // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max).
2368         ImVec2 canvas_pos;
2369         igGetCursorScreenPos(&canvas_pos);            // ImDrawList API uses screen coordinates!
2370         ImVec2 canvas_size;
2371         igGetContentRegionAvail(&canvas_size);        // Resize canvas to what's available
2372         if (canvas_size.x < 50.0f) canvas_size.x = 50.0f;
2373         if (canvas_size.y < 50.0f) canvas_size.y = 50.0f;
2374         draw_list.ImDrawList_AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), ImColor(50,50,50).asImU32, ImColor(50,50,60).asImU32, ImColor(60,60,70).asImU32, ImColor(50,50,60).asImU32);
2375         draw_list.ImDrawList_AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), ImColor(255,255,255).asImU32);
2376 
2377         bool adding_preview = false;
2378         igInvisibleButton("canvas", canvas_size);
2379         ImVec2 mouse_pos_in_canvas = ImVec2(igGetIO().MousePos.x - canvas_pos.x, igGetIO().MousePos.y - canvas_pos.y);
2380         if (adding_line)
2381         {
2382             adding_preview = true;
2383             points ~= mouse_pos_in_canvas;
2384             if (!igGetIO().MouseDown[0])
2385                 adding_line = adding_preview = false;
2386         }
2387         if (igIsItemHovered())
2388         {
2389             if (!adding_line && igIsMouseClicked(0))
2390             {
2391                 points ~= mouse_pos_in_canvas;
2392                 adding_line = true;
2393             }
2394             if (igIsMouseClicked(1) && points.length)
2395             {
2396                 adding_line = adding_preview = false;
2397                 points = points[0..$-2];
2398             }
2399         }
2400         draw_list.ImDrawList_PushClipRect(canvas_pos, ImVec2(canvas_pos.x+canvas_size.x, canvas_pos.y+canvas_size.y));      // clip lines within the canvas (if we resize it, etc.)
2401         for (int i = 0; i + 1 < points.length; i += 2)
2402             draw_list.ImDrawList_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);
2403         draw_list.ImDrawList_PopClipRect();
2404         if (adding_preview)
2405             points = points[0..$-1];
2406     }
2407     igEnd();
2408 }
2409 
2410 // Demonstrating creating a simple console window, with scrolling, filtering, completion and history.
2411 // For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions.
2412 class ExampleAppConsole
2413 {
2414     char[256]             InputBuf;
2415     string[]              Items;
2416     bool                  ScrollToBottom;
2417     string[]              History;
2418     int                   HistoryPos;    // -1: new line, 0..History.Size-1 browsing history.
2419     string[]              Commands;
2420 
2421     this()
2422     {
2423         ClearLog();
2424         InputBuf[] = 0;
2425         HistoryPos = -1;
2426         Commands ~= "HELP";
2427         Commands ~= "HISTORY";
2428         Commands ~= "CLEAR";
2429         Commands ~= "CLASSIFY";  // "classify" is here to provide an example of "C"+[tab] completing to "CL" and displaying matches.
2430         AddLog("Welcome to ImGui!");
2431     }
2432     ~this()
2433     {
2434         ClearLog();
2435         History = null;
2436     }
2437 
2438     // Portable helpers
2439     static int   Stricmp(const(char)* str1, const(char)* str2)         { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; }
2440     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; }
2441     static string Strdup(const(char)* str)                             { return to!string(str); }
2442 
2443     void    ClearLog()
2444     {
2445         Items = null;
2446         ScrollToBottom = true;
2447     }
2448 
2449     void    AddLog(Char, Args...)(in Char[] fmt, Args args)
2450     {
2451         Items ~= format(fmt, args);
2452         ScrollToBottom = true;
2453     }
2454 
2455     void    Draw(const(char)* title, bool* p_open)
2456     {
2457         igSetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver);
2458         if (!igBegin(title, p_open))
2459         {
2460             igEnd();
2461             return;
2462         }
2463 
2464         igTextWrapped("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.");
2465         igTextWrapped("Enter 'HELP' for help, press TAB to use text completion.");
2466 
2467         // TODO: display items starting from the bottom
2468 
2469         if (igSmallButton("Add Dummy Text")) { AddLog("%d some text", Items.length); AddLog("some more text"); AddLog("display very important message here!"); } igSameLine();
2470         if (igSmallButton("Add Dummy Error")) AddLog("[error] something went wrong"); igSameLine();
2471         if (igSmallButton("Clear")) ClearLog(); igSameLine();
2472         bool copy_to_clipboard = igSmallButton("Copy"); igSameLine();
2473         if (igSmallButton("Scroll to bottom")) ScrollToBottom = true;
2474         //static float t = 0.0f; if (igGetTime() - t > 0.02f) { t = igGetTime(); AddLog("Spam %f", t); }
2475 
2476         igSeparator();
2477 
2478         igPushStyleVarVec(ImGuiStyleVar_FramePadding, ImVec2(0,0));
2479         static ImGuiTextFilterWrapper filter;
2480         filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
2481         igPopStyleVar();
2482         igSeparator();
2483 
2484         igBeginChild("ScrollingRegion", ImVec2(0,-igGetFrameHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
2485         if (igBeginPopupContextWindow())
2486         {
2487             if (igSelectable("Clear")) ClearLog();
2488             igEndPopup();
2489         }
2490 
2491         // 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 igTextUnformatted(log.begin(), log.end());
2492         // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items.
2493         // 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.
2494         // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with:
2495         //     ImGuiListClipper clipper(Items.Size);
2496         //     while (clipper.Step())
2497         //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
2498         // However take note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list.
2499         // 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,
2500         // 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!
2501         // 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.
2502         igPushStyleVarVec(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing
2503         if (copy_to_clipboard)
2504             igLogToClipboard();
2505         for (int i = 0; i < Items.length; i++)
2506         {
2507             string item = Items[i];
2508             if (!filter.PassFilter(item.ptr, item.ptr + item.length))
2509                 continue;
2510             ImVec4 col = ImVec4(1.0f,1.0f,1.0f,1.0f); // A better implementation may store a type per-item. For the sample let's just parse the text.
2511             if (strstr(item.ptr, "[error]")) col = ImColor(1.0f,0.4f,0.4f,1.0f);
2512             else if (strncmp(item.ptr, "# ", 2) == 0) col = ImColor(1.0f,0.78f,0.58f,1.0f);
2513             igPushStyleColor(ImGuiCol_Text, col);
2514             igTextUnformatted(item.ptr, item.ptr + item.length);
2515             igPopStyleColor();
2516         }
2517         if (copy_to_clipboard)
2518             igLogFinish();
2519         if (ScrollToBottom)
2520             igSetScrollHere();
2521         ScrollToBottom = false;
2522         igPopStyleVar();
2523         igEndChild();
2524         igSeparator();
2525 
2526         // Command-line
2527         if (igInputText("Input", InputBuf.ptr, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue|ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, cast(void*)this))
2528         {
2529             char* input_end = InputBuf.ptr + strlen(InputBuf.ptr);
2530             while (input_end > InputBuf.ptr && input_end[-1] == ' ') input_end--; *input_end = 0;
2531             if (InputBuf[0])
2532                 ExecCommand(to!string(InputBuf.ptr[0..(input_end - InputBuf.ptr)]));
2533             strcpy(InputBuf.ptr, "");
2534         }
2535 
2536         // Demonstrate keeping auto focus on the input box
2537         if (igIsItemHovered() || (igIsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !igIsAnyItemActive() && !igIsMouseClicked(0)))
2538             igSetKeyboardFocusHere(-1); // Auto focus previous widget
2539 
2540         igEnd();
2541     }
2542 
2543     void    ExecCommand(string command_line)
2544     {
2545         AddLog("# %s\n", command_line);
2546 
2547         // 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.
2548         HistoryPos = -1;
2549         for (int i = cast(int)History.length - 1; i >= 0; i--)
2550             if (icmp(History[i], command_line) == 0)
2551             {
2552                 History = History.remove(i);
2553                 break;
2554             }
2555         History ~= command_line;
2556 
2557         // Process command
2558         if (icmp(command_line, "CLEAR") == 0)
2559         {
2560             ClearLog();
2561         }
2562         else if (icmp(command_line, "HELP") == 0)
2563         {
2564             AddLog("Commands:");
2565             for (int i = 0; i < Commands.length; i++)
2566                 AddLog("- %s", Commands[i]);
2567         }
2568         else if (icmp(command_line, "HISTORY") == 0)
2569         {
2570             for (int i = History.length >= 10 ? cast(int)History.length - 10 : 0; i < History.length; i++)
2571                 AddLog("%3d: %s\n", i, History[i]);
2572         }
2573         else
2574         {
2575             AddLog("Unknown command: '%s'\n", command_line);
2576         }
2577     }
2578 
2579     extern(C) nothrow static int TextEditCallbackStub(ImGuiTextEditCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks
2580     {
2581         ExampleAppConsole console = cast(ExampleAppConsole)data.UserData;
2582         return console.TextEditCallback(data);
2583     }
2584 
2585     nothrow int TextEditCallback(ImGuiTextEditCallbackData* data)
2586     {
2587         try {
2588             //AddLog("cursor: %d, selection: %d-%d", data.CursorPos, data.SelectionStart, data.SelectionEnd);
2589             switch (data.EventFlag)
2590             {
2591             case ImGuiInputTextFlags_CallbackCompletion:
2592                 {
2593                     // Example of TEXT COMPLETION
2594 
2595                     // Locate beginning of current word
2596                     const(char)* word_end = data.Buf + data.CursorPos;
2597                     const(char)* word_start = word_end;
2598                     while (word_start > data.Buf)
2599                     {
2600                         const char c = word_start[-1];
2601                         if (c == ' ' || c == '\t' || c == ',' || c == ';')
2602                             break;
2603                         word_start--;
2604                     }
2605 
2606                     // Build a list of candidates
2607                     string[] candidates;
2608                     for (int i = 0; i < Commands.length; i++) {
2609                         import std.algorithm.comparison : min;
2610                         auto n = word_end-word_start;
2611 
2612                         if (icmp(Commands[i][0..min(n, $)], word_start[0..n]) == 0)
2613                             candidates ~= Commands[i];
2614                     }
2615 
2616                     if (candidates.length == 0)
2617                     {
2618                         // No match
2619                         AddLog("No match for \"%s\"!\n", word_start[0..(word_end-word_start)]);
2620                     }
2621                     else if (candidates.length == 1)
2622                     {
2623                         // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing
2624                         data.DeleteChars(cast(int)(word_start-data.Buf), cast(int)(word_end-word_start));
2625                         data.InsertChars(data.CursorPos, candidates[0].ptr, candidates[0].ptr + candidates[0].length);
2626                         data.InsertChars(data.CursorPos, " ");
2627                     }
2628                     else
2629                     {
2630                         // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY"
2631                         int match_len = cast(int)(word_end - word_start);
2632                         for (;;)
2633                         {
2634                             int c = 0;
2635                             bool all_candidates_matches = true;
2636                             for (int i = 0; i < candidates.length && all_candidates_matches; i++)
2637                                 if (i == 0)
2638                                     c = toupper(candidates[i][match_len]);
2639                                 else if (c == 0 || c != toupper(candidates[i][match_len]))
2640                                     all_candidates_matches = false;
2641                             if (!all_candidates_matches)
2642                                 break;
2643                             match_len++;
2644                         }
2645 
2646                         if (match_len > 0)
2647                         {
2648                             data.DeleteChars(cast(int)(word_start - data.Buf), cast(int)(word_end-word_start));
2649                             data.InsertChars(data.CursorPos, candidates[0].ptr, candidates[0].ptr + match_len);
2650                         }
2651 
2652                         // List matches
2653                         AddLog("Possible matches:\n");
2654                         for (int i = 0; i < candidates.length; i++)
2655                             AddLog("- %s\n", candidates[i]);
2656                     }
2657 
2658                     break;
2659                 }
2660             case ImGuiInputTextFlags_CallbackHistory:
2661                 {
2662                     // Example of HISTORY
2663                     const int prev_history_pos = HistoryPos;
2664                     if (data.EventKey == ImGuiKey_UpArrow)
2665                     {
2666                         if (HistoryPos == -1)
2667                             HistoryPos = cast(int)History.length - 1;
2668                         else if (HistoryPos > 0)
2669                             HistoryPos--;
2670                     }
2671                     else if (data.EventKey == ImGuiKey_DownArrow)
2672                     {
2673                         if (HistoryPos != -1)
2674                             if (++HistoryPos >= History.length)
2675                                 HistoryPos = -1;
2676                     }
2677 
2678                     // A better implementation would preserve the data on the current input line along with cursor position.
2679                     if (prev_history_pos != HistoryPos)
2680                     {
2681                         data.CursorPos = data.SelectionStart = data.SelectionEnd = data.BufTextLen = cast(int)snprintf(data.Buf, cast(size_t)data.BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos].toStringz : "");
2682                         data.BufDirty = true;
2683                     }
2684                     break;
2685                 }
2686             default:
2687                 assert(false);
2688             }
2689             return 0;
2690         } catch(Exception e) {
2691             assert(false, e.toString);
2692         }
2693     }
2694 }
2695 
2696 void ShowExampleAppConsole(bool* p_open)
2697 {
2698     static ExampleAppConsole console;
2699     if(console is null) console = new ExampleAppConsole;
2700     console.Draw("Example: Console", p_open);
2701 }
2702 
2703 // Usage:
2704 //  static ExampleAppLog my_log;
2705 //  my_log.AddLog("Hello %d world\n", 123);
2706 //  my_log.Draw("title");
2707 struct ExampleAppLog
2708 {
2709     ImGuiTextBufferWrapper     Buf;
2710     ImGuiTextFilterWrapper     Filter;
2711     int[]               LineOffsets;        // Index to lines offset
2712     bool                ScrollToBottom;
2713 
2714     void    Clear()     { Buf.clear(); LineOffsets = null; }
2715 
2716     void    AddLog(const(char)* fmt, ...)
2717     {
2718         int old_size = Buf.size();
2719         va_list args;
2720         va_start(args, fmt);
2721         Buf.appendfv(fmt, args);
2722         va_end(args);
2723         for (int new_size = Buf.size(); old_size < new_size; old_size++)
2724             if (Buf[old_size] == '\n')
2725                 LineOffsets ~= old_size;
2726         ScrollToBottom = true;
2727     }
2728 
2729     void    Draw(const(char)* title, bool* p_open = null)
2730     {
2731         igSetNextWindowSize(ImVec2(500,400), ImGuiCond_FirstUseEver);
2732         igBegin(title, p_open);
2733         if (igButton("Clear")) Clear();
2734         igSameLine();
2735         bool copy = igButton("Copy");
2736         igSameLine();
2737         Filter.Draw("Filter", -100.0f);
2738         igSeparator();
2739         igBeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar);
2740         if (copy) igLogToClipboard();
2741 
2742         if (Filter.IsActive())
2743         {
2744             const(char)* buf_begin = Buf.begin();
2745             const(char)* line = buf_begin;
2746             for (int line_no = 0; line != null; line_no++)
2747             {
2748                 const(char)* line_end = (line_no < LineOffsets.length) ? buf_begin + LineOffsets[line_no] : null;
2749                 if (Filter.PassFilter(line, line_end))
2750                     igTextUnformatted(line, line_end);
2751                 line = line_end && line_end[1] ? line_end + 1 : null;
2752             }
2753         }
2754         else
2755         {
2756             igTextUnformatted(Buf.begin());
2757         }
2758 
2759         if (ScrollToBottom)
2760             igSetScrollHere(1.0f);
2761         ScrollToBottom = false;
2762         igEndChild();
2763         igEnd();
2764     }
2765 }
2766 
2767 // Demonstrate creating a simple log window with basic filtering.
2768 void ShowExampleAppLog(bool* p_open)
2769 {
2770     static ExampleAppLog log;
2771 
2772     // Demo: add random items (unless Ctrl is held)
2773     static float last_time = -1.0f;
2774     float time = igGetTime();
2775     if (time - last_time >= 0.20f && !igGetIO().KeyCtrl)
2776     {
2777         const(char)*[] random_words = [ "system", "info", "warning", "error", "fatal", "notice", "log" ];
2778         log.AddLog("[%s] Hello, time is %.1f, rand() %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, cast(int)rand());
2779         last_time = time;
2780     }
2781 
2782     log.Draw("Example: Log", p_open);
2783 }
2784 
2785 // Demonstrate create a window with multiple child windows.
2786 void ShowExampleAppLayout(bool* p_open)
2787 {
2788     igSetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
2789     if (igBegin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar))
2790     {
2791         if (igBeginMenuBar())
2792         {
2793             if (igBeginMenu("File"))
2794             {
2795                 if (igMenuItem("Close")) *p_open = false;
2796                 igEndMenu();
2797             }
2798             igEndMenuBar();
2799         }
2800 
2801         // left
2802         static int selected = 0;
2803         igBeginChild("left pane", ImVec2(150, 0), true);
2804         for (int i = 0; i < 100; i++)
2805         {
2806             char[128] label;
2807             sprintf(label.ptr, "MyObject %d", i);
2808             if (igSelectable(label.ptr, selected == i))
2809                 selected = i;
2810         }
2811         igEndChild();
2812         igSameLine();
2813 
2814         // right
2815         igBeginGroup();
2816             igBeginChild("item view", ImVec2(0, -igGetFrameHeightWithSpacing())); // Leave room for 1 line below us
2817                 igText("MyObject: %d", selected);
2818                 igSeparator();
2819                 igTextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
2820             igEndChild();
2821             igBeginChild("buttons");
2822                 if (igButton("Revert")) {}
2823                 igSameLine();
2824                 if (igButton("Save")) {}
2825             igEndChild();
2826         igEndGroup();
2827     }
2828     igEnd();
2829 }
2830 
2831 // Demonstrate create a simple property editor.
2832 void ShowExampleAppPropertyEditor(bool* p_open)
2833 {
2834     igSetNextWindowSize(ImVec2(430,450), ImGuiCond_FirstUseEver);
2835     if (!igBegin("Example: Property editor", p_open))
2836     {
2837         igEnd();
2838         return;
2839     }
2840 
2841     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 igSameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API.");
2842 
2843     igPushStyleVarVec(ImGuiStyleVar_FramePadding, ImVec2(2,2));
2844     igColumns(2);
2845     igSeparator();
2846 
2847     struct funcs
2848     {
2849         static void ShowDummyObject(const(char)* prefix, int uid)
2850         {
2851             igPushIDInt(uid);                      // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
2852             igAlignTextToFramePadding();  // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high.
2853             bool node_open = igTreeNodeStr("Object", "%s_%u", prefix, uid);
2854             igNextColumn();
2855             igAlignTextToFramePadding();
2856             igText("my sailor is rich");
2857             igNextColumn();
2858             if (node_open)
2859             {
2860                 static float[8] dummy_members = [ 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f ];
2861                 for (int i = 0; i < 8; i++)
2862                 {
2863                     igPushIDInt(i); // Use field index as identifier.
2864                     if (i < 2)
2865                     {
2866                         ShowDummyObject("Child", 424242);
2867                     }
2868                     else
2869                     {
2870                         igAlignTextToFramePadding();
2871                         // Here we use a Selectable (instead of Text) to highlight on hover
2872                         //igText("Field_%d", i);
2873                         char[32] label;
2874                         sprintf(label.ptr, "Field_%d", i);
2875                         igBullet();
2876                         igSelectable(label.ptr);
2877                         igNextColumn();
2878                         igPushItemWidth(-1);
2879                         if (i >= 5)
2880                             igInputFloat("##value", &dummy_members[i], 1.0f);
2881                         else
2882                             igDragFloat("##value", &dummy_members[i], 0.01f);
2883                         igPopItemWidth();
2884                         igNextColumn();
2885                     }
2886                     igPopID();
2887                 }
2888                 igTreePop();
2889             }
2890             igPopID();
2891         }
2892     }
2893 
2894     // Iterate dummy objects with dummy members (all the same data)
2895     for (int obj_i = 0; obj_i < 3; obj_i++)
2896         funcs.ShowDummyObject("Object", obj_i);
2897 
2898     igColumns(1);
2899     igSeparator();
2900     igPopStyleVar();
2901     igEnd();
2902 }
2903 
2904 // Demonstrate/test rendering huge amount of text, and the incidence of clipping.
2905 void ShowExampleAppLongText(bool* p_open)
2906 {
2907     igSetNextWindowSize(ImVec2(520,600), ImGuiCond_FirstUseEver);
2908     if (!igBegin("Example: Long text display", p_open))
2909     {
2910         igEnd();
2911         return;
2912     }
2913 
2914     static int test_type = 0;
2915     static ImGuiTextBufferWrapper log;
2916     static int lines = 0;
2917     igText("Printing unusually long amount of text.");
2918     igCombo2("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped\0");
2919     igText("Buffer contents: %d lines, %d bytes", lines, log.size());
2920     if (igButton("Clear")) { log.clear(); lines = 0; }
2921     igSameLine();
2922     if (igButton("Add 1000 lines"))
2923     {
2924         for (int i = 0; i < 1000; i++)
2925             log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines+i);
2926         lines += 1000;
2927     }
2928     igBeginChild("Log");
2929     switch (test_type)
2930     {
2931     case 0:
2932         // Single call to TextUnformatted() with a big buffer
2933         igTextUnformatted(log.begin(), log.end());
2934         break;
2935     case 1:
2936         {
2937             // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
2938             igPushStyleVarVec(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
2939             ImGuiListClipper clipper = ImGuiListClipper(lines);
2940             while (clipper.Step())
2941                 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
2942                     igText("%i The quick brown fox jumps over the lazy dog", i);
2943             igPopStyleVar();
2944             break;
2945         }
2946     case 2:
2947         // Multiple calls to Text(), not clipped (slow)
2948         igPushStyleVarVec(ImGuiStyleVar_ItemSpacing, ImVec2(0,0));
2949         for (int i = 0; i < lines; i++)
2950             igText("%i The quick brown fox jumps over the lazy dog", i);
2951         igPopStyleVar();
2952         break;
2953     default:
2954         assert(false);
2955     }
2956     igEndChild();
2957     igEnd();
2958 }
2959 
2960 // End of Demo code