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