Changeset e66fd66 in opengl-game for IMGUI/imgui_demo.cpp
- Timestamp:
- Dec 5, 2020, 7:14:31 PM (4 years ago)
- Branches:
- feature/imgui-sdl, master
- Children:
- 95c657f
- Parents:
- 78c3045
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
IMGUI/imgui_demo.cpp
r78c3045 re66fd66 1 // dear imgui, v1. 61 WIP1 // dear imgui, v1.79 2 2 // (demo code) 3 3 4 // Message to the person tempted to delete this file when integrating ImGui into their code base: 5 // Don't do it! Do NOT remove this file from your project! It is useful reference code that you and other users will want to refer to. 4 // Help: 5 // - Read FAQ at http://dearimgui.org/faq 6 // - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. 7 // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. 8 // Read imgui.cpp for more details, documentation and comments. 9 // Get latest version at https://github.com/ocornut/imgui 10 11 // Message to the person tempted to delete this file when integrating Dear ImGui into their code base: 12 // Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other 13 // coders will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available 14 // debug menu of your game/app! Removing this file from your project is hindering access to documentation for everyone 15 // in your team, likely leading you to poorer usage of the library. 6 16 // Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow(). 7 // During development, you can call ImGui::ShowDemoWindow() in your code to learn about various features of ImGui. Have it wired in a debug menu! 8 // Removing this file from your project is hindering access to documentation for everyone in your team, likely leading you to poorer usage of the library. 9 // Note that you can #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h for the same effect. 10 // If you want to link core ImGui in your final builds but not those demo windows, #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h and those functions will be empty. 11 // In other situation, when you have ImGui available you probably want this to be available for reference and execution. 17 // If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be 18 // linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty. 19 // In other situation, whenever you have Dear ImGui available you probably want this to be available for reference. 12 20 // Thank you, 13 // -Your beloved friend, imgui_demo.cpp (that you won't delete) 14 15 // Message to beginner C/C++ programmers. About the meaning of 'static': in this demo code, we frequently we use 'static' variables inside functions. 16 // We do this as a way to gather code and data in the same place, just to make the demo code faster to read, faster to write, and use less code. 17 // A static variable persist across calls, so it is essentially like a global variable but declared inside the scope of the function. 18 // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant or used in threads. 19 // This might be a pattern you occasionally want to use in your code, but most of the real data you would be editing is likely to be stored outside your function. 21 // -Your beloved friend, imgui_demo.cpp (which you won't delete) 22 23 // Message to beginner C/C++ programmers about the meaning of the 'static' keyword: 24 // In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, 25 // so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to 26 // gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller 27 // in size. It also happens to be a convenient way of storing simple UI related information as long as your function 28 // doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, 29 // but most of the real data you would be editing is likely going to be stored outside your functions. 30 31 // The Demo code in this file is designed to be easy to copy-and-paste in into your application! 32 // Because of this: 33 // - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. 34 // - We try to declare static variables in the local scope, as close as possible to the code using them. 35 // - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API. 36 // - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided 37 // by imgui_internal.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional 38 // and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. 39 // Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp. 40 41 /* 42 43 Index of this file: 44 45 // [SECTION] Forward Declarations, Helpers 46 // [SECTION] Demo Window / ShowDemoWindow() 47 // [SECTION] About Window / ShowAboutWindow() 48 // [SECTION] Style Editor / ShowStyleEditor() 49 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 50 // [SECTION] Example App: Debug Console / ShowExampleAppConsole() 51 // [SECTION] Example App: Debug Log / ShowExampleAppLog() 52 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 53 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 54 // [SECTION] Example App: Long Text / ShowExampleAppLongText() 55 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 56 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 57 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() 58 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() 59 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 60 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 61 62 */ 20 63 21 64 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) … … 24 67 25 68 #include "imgui.h" 26 #include <ctype.h> // toupper, isprint 69 #ifndef IMGUI_DISABLE 70 71 #include <ctype.h> // toupper 72 #include <limits.h> // INT_MIN, INT_MAX 27 73 #include <math.h> // sqrtf, powf, cosf, sinf, floorf, ceilf 28 74 #include <stdio.h> // vsnprintf, sscanf, printf … … 34 80 #endif 35 81 82 // Visual Studio warnings 36 83 #ifdef _MSC_VER 37 84 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen 38 #define snprintf _snprintf39 85 #endif 40 #ifdef __clang__ 41 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse. 42 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code) 43 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' 44 #pragma clang diagnostic ignored "-Wformat-security" // warning : warning: format string is not a string literal 45 #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. 46 #if __has_warning("-Wreserved-id-macro") 47 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier // 86 87 // Clang/GCC warnings with -Weverything 88 #if defined(__clang__) 89 #if __has_warning("-Wunknown-warning-option") 90 #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! 48 91 #endif 92 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' 93 #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. 94 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code) 95 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 96 #pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal 97 #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. 98 #pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. 99 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 100 #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. 101 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier 102 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision 49 103 #elif defined(__GNUC__) 50 #pragma GCC diagnostic ignored "-W int-to-pointer-cast" // warning: cast to pointer from integer of different size51 #pragma GCC diagnostic ignored "-W format-security" // warning : format string is not a string literal (potentially insecure)52 #pragma GCC diagnostic ignored "-W double-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function53 #pragma GCC diagnostic ignored "-W conversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value54 # if (__GNUC__ >= 6)55 #pragma GCC diagnostic ignored "-Wmisleading-indentation" //warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub.104 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind 105 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size 106 #pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) 107 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function 108 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value 109 #pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. 56 110 #endif 111 112 // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) 113 #ifdef _WIN32 114 #define IM_NEWLINE "\r\n" 115 #else 116 #define IM_NEWLINE "\n" 57 117 #endif 58 118 59 // Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n. 60 #ifdef _WIN32 61 #define IM_NEWLINE "\r\n" 62 #else 63 #define IM_NEWLINE "\n" 119 // Helpers 120 #if defined(_MSC_VER) && !defined(snprintf) 121 #define snprintf _snprintf 64 122 #endif 65 66 #define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B)) 123 #if defined(_MSC_VER) && !defined(vsnprintf) 124 #define vsnprintf _vsnprintf 125 #endif 126 127 // Helpers macros 128 // We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste, 129 // but making an exception here as those are largely simplifying code... 130 // In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo. 131 #define IM_MIN(A, B) (((A) < (B)) ? (A) : (B)) 132 #define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) 133 #define IM_CLAMP(V, MN, MX) ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V)) 67 134 68 135 //----------------------------------------------------------------------------- 69 // DEMO CODE136 // [SECTION] Forward Declarations, Helpers 70 137 //----------------------------------------------------------------------------- 71 138 72 #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Obsolete name since 1.53, TEST->DEMO73 #define IMGUI_DISABLE_DEMO_WINDOWS74 #endif75 76 139 #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) 77 140 141 // Forward Declarations 142 static void ShowExampleAppDocuments(bool* p_open); 143 static void ShowExampleAppMainMenuBar(); 78 144 static void ShowExampleAppConsole(bool* p_open); 79 145 static void ShowExampleAppLog(bool* p_open); … … 83 149 static void ShowExampleAppAutoResize(bool* p_open); 84 150 static void ShowExampleAppConstrainedResize(bool* p_open); 85 static void ShowExampleApp FixedOverlay(bool* p_open);151 static void ShowExampleAppSimpleOverlay(bool* p_open); 86 152 static void ShowExampleAppWindowTitles(bool* p_open); 87 153 static void ShowExampleAppCustomRendering(bool* p_open); 88 static void ShowExampleAppMainMenuBar();89 154 static void ShowExampleMenuFile(); 90 155 91 static void ShowHelpMarker(const char* desc) 156 // Helper to display a little (?) mark which shows a tooltip when hovered. 157 // In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) 158 static void HelpMarker(const char* desc) 92 159 { 93 ImGui::TextDisabled("(?)");94 if (ImGui::IsItemHovered())95 {96 ImGui::BeginTooltip();97 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);98 ImGui::TextUnformatted(desc);99 ImGui::PopTextWrapPos();100 ImGui::EndTooltip();101 }160 ImGui::TextDisabled("(?)"); 161 if (ImGui::IsItemHovered()) 162 { 163 ImGui::BeginTooltip(); 164 ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 165 ImGui::TextUnformatted(desc); 166 ImGui::PopTextWrapPos(); 167 ImGui::EndTooltip(); 168 } 102 169 } 103 170 171 // Helper to display basic user controls. 104 172 void ImGui::ShowUserGuide() 105 173 { 106 ImGui::BulletText("Double-click on title bar to collapse window."); 107 ImGui::BulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents)."); 108 ImGui::BulletText("Click and drag on any empty space to move window."); 109 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); 110 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); 111 if (ImGui::GetIO().FontAllowUserScaling) 112 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); 113 ImGui::BulletText("Mouse Wheel to scroll."); 114 ImGui::BulletText("While editing text:\n"); 115 ImGui::Indent(); 116 ImGui::BulletText("Hold SHIFT or use mouse to select text."); 117 ImGui::BulletText("CTRL+Left/Right to word jump."); 118 ImGui::BulletText("CTRL+A or double-click to select all."); 119 ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard."); 120 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); 121 ImGui::BulletText("ESCAPE to revert."); 122 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); 123 ImGui::Unindent(); 174 ImGuiIO& io = ImGui::GetIO(); 175 ImGui::BulletText("Double-click on title bar to collapse window."); 176 ImGui::BulletText( 177 "Click and drag on lower corner to resize window\n" 178 "(double-click to auto fit window to its contents)."); 179 ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); 180 ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); 181 if (io.FontAllowUserScaling) 182 ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); 183 ImGui::BulletText("While inputing text:\n"); 184 ImGui::Indent(); 185 ImGui::BulletText("CTRL+Left/Right to word jump."); 186 ImGui::BulletText("CTRL+A or double-click to select all."); 187 ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); 188 ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); 189 ImGui::BulletText("ESCAPE to revert."); 190 ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract."); 191 ImGui::Unindent(); 192 ImGui::BulletText("With keyboard navigation enabled:"); 193 ImGui::Indent(); 194 ImGui::BulletText("Arrow keys to navigate."); 195 ImGui::BulletText("Space to activate a widget."); 196 ImGui::BulletText("Return to input text into a widget."); 197 ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); 198 ImGui::BulletText("Alt to jump to the menu layer of a window."); 199 ImGui::BulletText("CTRL+Tab to select a window."); 200 ImGui::Unindent(); 124 201 } 125 202 126 // Demonstrate most ImGui features (big function!) 203 //----------------------------------------------------------------------------- 204 // [SECTION] Demo Window / ShowDemoWindow() 205 //----------------------------------------------------------------------------- 206 // - ShowDemoWindowWidgets() 207 // - ShowDemoWindowLayout() 208 // - ShowDemoWindowPopups() 209 // - ShowDemoWindowColumns() 210 // - ShowDemoWindowMisc() 211 //----------------------------------------------------------------------------- 212 213 // We split the contents of the big ShowDemoWindow() function into smaller functions 214 // (because the link time of very large functions grow non-linearly) 215 static void ShowDemoWindowWidgets(); 216 static void ShowDemoWindowLayout(); 217 static void ShowDemoWindowPopups(); 218 static void ShowDemoWindowColumns(); 219 static void ShowDemoWindowMisc(); 220 221 // Demonstrate most Dear ImGui features (this is big function!) 222 // You may execute this function to experiment with the UI and understand what it does. 223 // You may then search for keywords in the code when you are interested by a specific feature. 127 224 void ImGui::ShowDemoWindow(bool* p_open) 128 225 { 129 // Examples apps 130 static bool show_app_main_menu_bar = false; 131 static bool show_app_console = false; 132 static bool show_app_log = false; 133 static bool show_app_layout = false; 134 static bool show_app_property_editor = false; 135 static bool show_app_long_text = false; 136 static bool show_app_auto_resize = false; 137 static bool show_app_constrained_resize = false; 138 static bool show_app_fixed_overlay = false; 139 static bool show_app_window_titles = false; 140 static bool show_app_custom_rendering = false; 141 static bool show_app_style_editor = false; 142 143 static bool show_app_metrics = false; 144 static bool show_app_about = false; 145 146 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); 147 if (show_app_console) ShowExampleAppConsole(&show_app_console); 148 if (show_app_log) ShowExampleAppLog(&show_app_log); 149 if (show_app_layout) ShowExampleAppLayout(&show_app_layout); 150 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); 151 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); 152 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); 153 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); 154 if (show_app_fixed_overlay) ShowExampleAppFixedOverlay(&show_app_fixed_overlay); 155 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); 156 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); 157 158 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } 159 if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); } 160 if (show_app_about) 161 { 162 ImGui::Begin("About Dear ImGui", &show_app_about, ImGuiWindowFlags_AlwaysAutoResize); 163 ImGui::Text("Dear ImGui, %s", ImGui::GetVersion()); 164 ImGui::Separator(); 165 ImGui::Text("By Omar Cornut and all dear imgui contributors."); 166 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); 167 ImGui::End(); 168 } 169 170 static bool no_titlebar = false; 171 static bool no_scrollbar = false; 172 static bool no_menu = false; 173 static bool no_move = false; 174 static bool no_resize = false; 175 static bool no_collapse = false; 176 static bool no_close = false; 177 static bool no_nav = false; 178 179 // Demonstrate the various window flags. Typically you would just use the default. 180 ImGuiWindowFlags window_flags = 0; 181 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; 182 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; 183 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; 184 if (no_move) window_flags |= ImGuiWindowFlags_NoMove; 185 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; 186 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; 187 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; 188 if (no_close) p_open = NULL; // Don't pass our bool* to Begin 189 190 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); 191 if (!ImGui::Begin("ImGui Demo", p_open, window_flags)) 192 { 193 // Early out if the window is collapsed, as an optimization. 194 ImGui::End(); 195 return; 196 } 197 198 //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // 2/3 of the space for widget and 1/3 for labels 199 ImGui::PushItemWidth(-140); // Right align, keep 140 pixels for labels 200 201 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); 202 203 // Menu 204 if (ImGui::BeginMenuBar()) 205 { 206 if (ImGui::BeginMenu("Menu")) 207 { 208 ShowExampleMenuFile(); 209 ImGui::EndMenu(); 210 } 211 if (ImGui::BeginMenu("Examples")) 212 { 213 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); 214 ImGui::MenuItem("Console", NULL, &show_app_console); 215 ImGui::MenuItem("Log", NULL, &show_app_log); 216 ImGui::MenuItem("Simple layout", NULL, &show_app_layout); 217 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); 218 ImGui::MenuItem("Long text display", NULL, &show_app_long_text); 219 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); 220 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); 221 ImGui::MenuItem("Simple overlay", NULL, &show_app_fixed_overlay); 222 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); 223 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); 224 ImGui::EndMenu(); 225 } 226 if (ImGui::BeginMenu("Help")) 227 { 228 ImGui::MenuItem("Metrics", NULL, &show_app_metrics); 229 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); 230 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); 231 ImGui::EndMenu(); 232 } 233 ImGui::EndMenuBar(); 234 } 235 236 ImGui::Spacing(); 237 if (ImGui::CollapsingHeader("Help")) 238 { 239 ImGui::TextWrapped("This window is being created by the ShowDemoWindow() function. Please refer to the code in imgui_demo.cpp for reference.\n\n"); 240 ImGui::Text("USER GUIDE:"); 241 ImGui::ShowUserGuide(); 242 } 243 244 if (ImGui::CollapsingHeader("Window options")) 245 { 246 ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); 247 ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); 248 ImGui::Checkbox("No menu", &no_menu); 249 ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); 250 ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); 251 ImGui::Checkbox("No collapse", &no_collapse); 252 ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); 253 ImGui::Checkbox("No nav", &no_nav); 254 255 if (ImGui::TreeNode("Style")) 256 { 257 ImGui::ShowStyleEditor(); 258 ImGui::TreePop(); 259 } 260 261 if (ImGui::TreeNode("Capture/Logging")) 262 { 263 ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded. You can also call ImGui::LogText() to output directly to the log without a visual output."); 264 ImGui::LogButtons(); 265 ImGui::TreePop(); 266 } 267 } 268 269 if (ImGui::CollapsingHeader("Widgets")) 270 { 271 if (ImGui::TreeNode("Basic")) 272 { 273 static int clicked = 0; 274 if (ImGui::Button("Button")) 226 // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup 227 // Most ImGui functions would normally just crash if the context is missing. 228 IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); 229 230 // Examples Apps (accessible from the "Examples" menu) 231 static bool show_app_main_menu_bar = false; 232 static bool show_app_documents = false; 233 static bool show_app_console = false; 234 static bool show_app_log = false; 235 static bool show_app_layout = false; 236 static bool show_app_property_editor = false; 237 static bool show_app_long_text = false; 238 static bool show_app_auto_resize = false; 239 static bool show_app_constrained_resize = false; 240 static bool show_app_simple_overlay = false; 241 static bool show_app_window_titles = false; 242 static bool show_app_custom_rendering = false; 243 244 if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); 245 if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); 246 247 if (show_app_console) ShowExampleAppConsole(&show_app_console); 248 if (show_app_log) ShowExampleAppLog(&show_app_log); 249 if (show_app_layout) ShowExampleAppLayout(&show_app_layout); 250 if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); 251 if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); 252 if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); 253 if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); 254 if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); 255 if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); 256 if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); 257 258 // Dear ImGui Apps (accessible from the "Tools" menu) 259 static bool show_app_metrics = false; 260 static bool show_app_style_editor = false; 261 static bool show_app_about = false; 262 263 if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } 264 if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } 265 if (show_app_style_editor) 266 { 267 ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); 268 ImGui::ShowStyleEditor(); 269 ImGui::End(); 270 } 271 272 // Demonstrate the various window flags. Typically you would just use the default! 273 static bool no_titlebar = false; 274 static bool no_scrollbar = false; 275 static bool no_menu = false; 276 static bool no_move = false; 277 static bool no_resize = false; 278 static bool no_collapse = false; 279 static bool no_close = false; 280 static bool no_nav = false; 281 static bool no_background = false; 282 static bool no_bring_to_front = false; 283 284 ImGuiWindowFlags window_flags = 0; 285 if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar; 286 if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; 287 if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; 288 if (no_move) window_flags |= ImGuiWindowFlags_NoMove; 289 if (no_resize) window_flags |= ImGuiWindowFlags_NoResize; 290 if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; 291 if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; 292 if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; 293 if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; 294 if (no_close) p_open = NULL; // Don't pass our bool* to Begin 295 296 // We specify a default position/size in case there's no data in the .ini file. 297 // We only do it to make the demo applications a little more welcoming, but typically this isn't required. 298 ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); 299 ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver); 300 301 // Main body of the Demo window starts here. 302 if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) 303 { 304 // Early out if the window is collapsed, as an optimization. 305 ImGui::End(); 306 return; 307 } 308 309 // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. 310 311 // e.g. Use 2/3 of the space for widgets and 1/3 for labels (default) 312 //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); 313 314 // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. 315 ImGui::PushItemWidth(ImGui::GetFontSize() * -12); 316 317 // Menu Bar 318 if (ImGui::BeginMenuBar()) 319 { 320 if (ImGui::BeginMenu("Menu")) 321 { 322 ShowExampleMenuFile(); 323 ImGui::EndMenu(); 324 } 325 if (ImGui::BeginMenu("Examples")) 326 { 327 ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); 328 ImGui::MenuItem("Console", NULL, &show_app_console); 329 ImGui::MenuItem("Log", NULL, &show_app_log); 330 ImGui::MenuItem("Simple layout", NULL, &show_app_layout); 331 ImGui::MenuItem("Property editor", NULL, &show_app_property_editor); 332 ImGui::MenuItem("Long text display", NULL, &show_app_long_text); 333 ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); 334 ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); 335 ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); 336 ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); 337 ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); 338 ImGui::MenuItem("Documents", NULL, &show_app_documents); 339 ImGui::EndMenu(); 340 } 341 if (ImGui::BeginMenu("Tools")) 342 { 343 ImGui::MenuItem("Metrics", NULL, &show_app_metrics); 344 ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); 345 ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); 346 ImGui::EndMenu(); 347 } 348 ImGui::EndMenuBar(); 349 } 350 351 ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); 352 ImGui::Spacing(); 353 354 if (ImGui::CollapsingHeader("Help")) 355 { 356 ImGui::Text("ABOUT THIS DEMO:"); 357 ImGui::BulletText("Sections below are demonstrating many aspects of the library."); 358 ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); 359 ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" 360 "and Metrics (general purpose Dear ImGui debugging tool)."); 361 ImGui::Separator(); 362 363 ImGui::Text("PROGRAMMER GUIDE:"); 364 ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); 365 ImGui::BulletText("See comments in imgui.cpp."); 366 ImGui::BulletText("See example applications in the examples/ folder."); 367 ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/"); 368 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls."); 369 ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls."); 370 ImGui::Separator(); 371 372 ImGui::Text("USER GUIDE:"); 373 ImGui::ShowUserGuide(); 374 } 375 376 if (ImGui::CollapsingHeader("Configuration")) 377 { 378 ImGuiIO& io = ImGui::GetIO(); 379 380 if (ImGui::TreeNode("Configuration##2")) 381 { 382 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); 383 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); 384 ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); 385 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); 386 ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); 387 ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouse); 388 389 // The "NoMouse" option above can get us stuck with a disable mouse! Provide an alternative way to fix it: 390 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) 391 { 392 if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) 393 { 394 ImGui::SameLine(); 395 ImGui::Text("<<PRESS SPACE TO DISABLE>>"); 396 } 397 if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) 398 io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; 399 } 400 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); 401 ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); 402 ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); 403 ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); 404 ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); 405 ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); 406 ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); 407 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); 408 ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. 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)."); 409 ImGui::Text("Also see Style->Rendering for rendering options."); 410 ImGui::TreePop(); 411 ImGui::Separator(); 412 } 413 414 if (ImGui::TreeNode("Backend Flags")) 415 { 416 HelpMarker( 417 "Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\n" 418 "Here we expose then as read-only fields to avoid breaking interactions with your back-end."); 419 420 // Make a local copy to avoid modifying actual back-end flags. 421 ImGuiBackendFlags backend_flags = io.BackendFlags; 422 ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasGamepad); 423 ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasMouseCursors); 424 ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasSetMousePos); 425 ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int*)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); 426 ImGui::TreePop(); 427 ImGui::Separator(); 428 } 429 430 if (ImGui::TreeNode("Style")) 431 { 432 HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); 433 ImGui::ShowStyleEditor(); 434 ImGui::TreePop(); 435 ImGui::Separator(); 436 } 437 438 if (ImGui::TreeNode("Capture/Logging")) 439 { 440 HelpMarker( 441 "The logging API redirects all text output so you can easily capture the content of " 442 "a window or a block. Tree nodes can be automatically expanded.\n" 443 "Try opening any of the contents below in this window and then click one of the \"Log To\" button."); 444 ImGui::LogButtons(); 445 446 HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output."); 447 if (ImGui::Button("Copy \"Hello, world!\" to clipboard")) 448 { 449 ImGui::LogToClipboard(); 450 ImGui::LogText("Hello, world!"); 451 ImGui::LogFinish(); 452 } 453 ImGui::TreePop(); 454 } 455 } 456 457 if (ImGui::CollapsingHeader("Window options")) 458 { 459 ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150); 460 ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300); 461 ImGui::Checkbox("No menu", &no_menu); 462 ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150); 463 ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300); 464 ImGui::Checkbox("No collapse", &no_collapse); 465 ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150); 466 ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300); 467 ImGui::Checkbox("No background", &no_background); 468 ImGui::Checkbox("No bring to front", &no_bring_to_front); 469 } 470 471 // All demo contents 472 ShowDemoWindowWidgets(); 473 ShowDemoWindowLayout(); 474 ShowDemoWindowPopups(); 475 ShowDemoWindowColumns(); 476 ShowDemoWindowMisc(); 477 478 // End of ShowDemoWindow() 479 ImGui::End(); 480 } 481 482 static void ShowDemoWindowWidgets() 483 { 484 if (!ImGui::CollapsingHeader("Widgets")) 485 return; 486 487 if (ImGui::TreeNode("Basic")) 488 { 489 static int clicked = 0; 490 if (ImGui::Button("Button")) 275 491 clicked++; 276 277 492 if (clicked & 1) 493 { 278 494 ImGui::SameLine(); 279 495 ImGui::Text("Thanks for clicking me!"); 280 } 281 282 static bool check = true; 283 ImGui::Checkbox("checkbox", &check); 284 285 static int e = 0; 286 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); 287 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); 288 ImGui::RadioButton("radio c", &e, 2); 289 290 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. 291 for (int i = 0; i < 7; i++) 292 { 293 if (i > 0) ImGui::SameLine(); 496 } 497 498 static bool check = true; 499 ImGui::Checkbox("checkbox", &check); 500 501 static int e = 0; 502 ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); 503 ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); 504 ImGui::RadioButton("radio c", &e, 2); 505 506 // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. 507 for (int i = 0; i < 7; i++) 508 { 509 if (i > 0) 510 ImGui::SameLine(); 294 511 ImGui::PushID(i); 295 512 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); … … 299 516 ImGui::PopStyleColor(3); 300 517 ImGui::PopID(); 301 } 302 303 // Arrow buttons 304 float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 305 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) {} 306 ImGui::SameLine(0.0f, spacing); 307 if (ImGui::ArrowButton("##left", ImGuiDir_Right)) {} 308 309 ImGui::Text("Hover over me"); 310 if (ImGui::IsItemHovered()) 518 } 519 520 // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements 521 // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) 522 // See 'Demo->Layout->Text Baseline Alignment' for details. 523 ImGui::AlignTextToFramePadding(); 524 ImGui::Text("Hold to repeat:"); 525 ImGui::SameLine(); 526 527 // Arrow buttons with Repeater 528 static int counter = 0; 529 float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 530 ImGui::PushButtonRepeat(true); 531 if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } 532 ImGui::SameLine(0.0f, spacing); 533 if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } 534 ImGui::PopButtonRepeat(); 535 ImGui::SameLine(); 536 ImGui::Text("%d", counter); 537 538 ImGui::Text("Hover over me"); 539 if (ImGui::IsItemHovered()) 311 540 ImGui::SetTooltip("I am a tooltip"); 312 541 313 314 315 316 542 ImGui::SameLine(); 543 ImGui::Text("- or me"); 544 if (ImGui::IsItemHovered()) 545 { 317 546 ImGui::BeginTooltip(); 318 547 ImGui::Text("I am a fancy tooltip"); … … 320 549 ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); 321 550 ImGui::EndTooltip(); 322 323 324 325 326 327 328 551 } 552 553 ImGui::Separator(); 554 555 ImGui::LabelText("label", "Value"); 556 557 { 329 558 // Using the _simplified_ one-liner Combo() api here 330 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 559 // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. 560 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; 331 561 static int item_current = 0; 332 562 ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); 333 ImGui::SameLine(); ShowHelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n"); 334 } 335 336 { 563 ImGui::SameLine(); HelpMarker( 564 "Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, " 565 "and demonstration of various flags.\n"); 566 } 567 568 { 569 // To wire InputText() with std::string or any other custom string type, 570 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 337 571 static char str0[128] = "Hello, world!"; 572 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); 573 ImGui::SameLine(); HelpMarker( 574 "USER:\n" 575 "Hold SHIFT or use mouse to select text.\n" 576 "CTRL+Left/Right to word jump.\n" 577 "CTRL+A or double-click to select all.\n" 578 "CTRL+X,CTRL+C,CTRL+V clipboard.\n" 579 "CTRL+Z,CTRL+Y undo/redo.\n" 580 "ESCAPE to revert.\n\n" 581 "PROGRAMMER:\n" 582 "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " 583 "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " 584 "in imgui_demo.cpp)."); 585 586 static char str1[128] = ""; 587 ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); 588 338 589 static int i0 = 123; 339 ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));340 ImGui::SameLine(); ShowHelpMarker("Hold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n");341 342 590 ImGui::InputInt("input int", &i0); 343 ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n"); 591 ImGui::SameLine(); HelpMarker( 592 "You can apply arithmetic operators +,*,/ on numerical values.\n" 593 " e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n" 594 "Use +- to subtract."); 344 595 345 596 static float f0 = 0.001f; 346 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f );347 348 static double d0 = 999999.00000 1;349 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%. 6f");597 ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); 598 599 static double d0 = 999999.00000001; 600 ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); 350 601 351 602 static float f1 = 1.e10f; 352 603 ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); 353 ImGui::SameLine(); ShowHelpMarker("You can input value using the scientific notation,\n e.g. \"1e+8\" becomes \"100000000\".\n"); 604 ImGui::SameLine(); HelpMarker( 605 "You can input value using the scientific notation,\n" 606 " e.g. \"1e+8\" becomes \"100000000\"."); 354 607 355 608 static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 356 609 ImGui::InputFloat3("input float3", vec4a); 357 358 359 610 } 611 612 { 360 613 static int i1 = 50, i2 = 42; 361 614 ImGui::DragInt("drag int", &i1, 1); 362 ImGui::SameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value."); 363 364 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%"); 615 ImGui::SameLine(); HelpMarker( 616 "Click and drag to edit value.\n" 617 "Hold SHIFT/ALT for faster/slower edit.\n" 618 "Double-click or CTRL+click to input value."); 619 620 ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); 365 621 366 622 static float f1 = 1.00f, f2 = 0.0067f; 367 623 ImGui::DragFloat("drag float", &f1, 0.005f); 368 624 ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); 369 370 371 625 } 626 627 { 372 628 static int i1 = 0; 373 629 ImGui::SliderInt("slider int", &i1, -1, 3); 374 ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value.");630 ImGui::SameLine(); HelpMarker("CTRL+click to input value."); 375 631 376 632 static float f1 = 0.123f, f2 = 0.0f; 377 633 ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); 378 ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f); 634 ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); 635 379 636 static float angle = 0.0f; 380 637 ImGui::SliderAngle("slider angle", &angle); 381 } 382 383 { 384 static float col1[3] = { 1.0f,0.0f,0.2f }; 385 static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; 638 639 // Using the format string to display a name instead of an integer. 640 // Here we completely omit '%d' from the format string, so it'll only display a name. 641 // This technique can also be used with DragInt(). 642 enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; 643 static int elem = Element_Fire; 644 const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; 645 const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; 646 ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); 647 ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); 648 } 649 650 { 651 static float col1[3] = { 1.0f, 0.0f, 0.2f }; 652 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 386 653 ImGui::ColorEdit3("color 1", col1); 387 ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n"); 654 ImGui::SameLine(); HelpMarker( 655 "Click on the colored square to open a color picker.\n" 656 "Click and hold to use drag and drop.\n" 657 "Right-click on the colored square to show options.\n" 658 "CTRL+click on individual component to input value.\n"); 388 659 389 660 ImGui::ColorEdit4("color 2", col2); 390 391 392 661 } 662 663 { 393 664 // List box 394 const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };395 static int listbox_item_current = 1;396 ImGui::ListBox("listbox\n(single select)", & listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4);665 const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; 666 static int item_current = 1; 667 ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4); 397 668 398 669 //static int listbox_item_current2 = 2; 399 //ImGui:: PushItemWidth(-1);670 //ImGui::SetNextItemWidth(-1); 400 671 //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); 401 //ImGui::PopItemWidth(); 402 } 403 404 ImGui::TreePop(); 405 } 406 407 // Testing ImGuiOnceUponAFrame helper. 408 //static ImGuiOnceUponAFrame once; 409 //for (int i = 0; i < 5; i++) 410 // if (once) 411 // ImGui::Text("This will be displayed only once."); 412 413 if (ImGui::TreeNode("Trees")) 414 { 415 if (ImGui::TreeNode("Basic trees")) 416 { 672 } 673 674 ImGui::TreePop(); 675 } 676 677 // Testing ImGuiOnceUponAFrame helper. 678 //static ImGuiOnceUponAFrame once; 679 //for (int i = 0; i < 5; i++) 680 // if (once) 681 // ImGui::Text("This will be displayed only once."); 682 683 if (ImGui::TreeNode("Trees")) 684 { 685 if (ImGui::TreeNode("Basic trees")) 686 { 417 687 for (int i = 0; i < 5; i++) 418 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) 419 { 420 ImGui::Text("blah blah"); 421 ImGui::SameLine(); 422 if (ImGui::SmallButton("button")) {}; 423 ImGui::TreePop(); 424 } 688 { 689 // Use SetNextItemOpen() so set the default state of a node to be open. We could 690 // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! 691 if (i == 0) 692 ImGui::SetNextItemOpen(true, ImGuiCond_Once); 693 694 if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) 695 { 696 ImGui::Text("blah blah"); 697 ImGui::SameLine(); 698 if (ImGui::SmallButton("button")) {} 699 ImGui::TreePop(); 700 } 701 } 425 702 ImGui::TreePop(); 426 } 427 428 if (ImGui::TreeNode("Advanced, with Selectable nodes")) 429 { 430 ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open."); 703 } 704 705 if (ImGui::TreeNode("Advanced, with Selectable nodes")) 706 { 707 HelpMarker( 708 "This is a more typical looking tree with selectable nodes.\n" 709 "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); 710 static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; 431 711 static bool align_label_with_current_x_position = false; 432 ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position); 712 static bool test_drag_and_drop = false; 713 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow); 714 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); 715 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); 716 ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth); 717 ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); 718 ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); 433 719 ImGui::Text("Hello!"); 434 720 if (align_label_with_current_x_position) 435 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); 436 437 static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit. 438 int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc. 439 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize() * 3); // Increase spacing to differentiate leaves from expanded contents. 721 ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); 722 723 // 'selection_mask' is dumb representation of what may be user-side selection state. 724 // You may retain selection state inside or outside your objects in whatever format you see fit. 725 // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end 726 /// of the loop. May be a pointer to your own node type, etc. 727 static int selection_mask = (1 << 2); 728 int node_clicked = -1; 440 729 for (int i = 0; i < 6; i++) 441 730 { 442 // Disable the default open on single-click behavior and pass in Selected flag according to our selection state. 443 ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0); 444 if (i < 3) 445 { 446 // Node 447 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); 448 if (ImGui::IsItemClicked()) 449 node_clicked = i; 450 if (node_open) 451 { 452 ImGui::Text("Blah blah\nBlah Blah"); 453 ImGui::TreePop(); 454 } 455 } 456 else 457 { 458 // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text(). 459 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet 460 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); 461 if (ImGui::IsItemClicked()) 462 node_clicked = i; 463 } 731 // Disable the default "open on single-click behavior" + set Selected flag according to our selection. 732 ImGuiTreeNodeFlags node_flags = base_flags; 733 const bool is_selected = (selection_mask & (1 << i)) != 0; 734 if (is_selected) 735 node_flags |= ImGuiTreeNodeFlags_Selected; 736 if (i < 3) 737 { 738 // Items 0..2 are Tree Node 739 bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); 740 if (ImGui::IsItemClicked()) 741 node_clicked = i; 742 if (test_drag_and_drop && ImGui::BeginDragDropSource()) 743 { 744 ImGui::SetDragDropPayload("_TREENODE", NULL, 0); 745 ImGui::Text("This is a drag and drop source"); 746 ImGui::EndDragDropSource(); 747 } 748 if (node_open) 749 { 750 ImGui::BulletText("Blah blah\nBlah Blah"); 751 ImGui::TreePop(); 752 } 753 } 754 else 755 { 756 // Items 3..5 are Tree Leaves 757 // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can 758 // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). 759 node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet 760 ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); 761 if (ImGui::IsItemClicked()) 762 node_clicked = i; 763 if (test_drag_and_drop && ImGui::BeginDragDropSource()) 764 { 765 ImGui::SetDragDropPayload("_TREENODE", NULL, 0); 766 ImGui::Text("This is a drag and drop source"); 767 ImGui::EndDragDropSource(); 768 } 769 } 464 770 } 465 771 if (node_clicked != -1) 466 772 { 467 // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.468 if (ImGui::GetIO().KeyCtrl)469 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle470 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 selection471 selection_mask = (1 << node_clicked); // Click to single-select472 }473 ImGui::PopStyleVar();773 // Update selection state 774 // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) 775 if (ImGui::GetIO().KeyCtrl) 776 selection_mask ^= (1 << node_clicked); // CTRL+click to toggle 777 else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection 778 selection_mask = (1 << node_clicked); // Click to single-select 779 } 474 780 if (align_label_with_current_x_position) 475 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());781 ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); 476 782 ImGui::TreePop(); 477 478 479 480 481 482 483 484 ImGui::Checkbox("Enable extra group", &closable_group);485 if (ImGui::CollapsingHeader("Header"))486 487 ImGui::Text("IsItemHovered: %d", I sItemHovered());783 } 784 ImGui::TreePop(); 785 } 786 787 if (ImGui::TreeNode("Collapsing Headers")) 788 { 789 static bool closable_group = true; 790 ImGui::Checkbox("Show 2nd header", &closable_group); 791 if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) 792 { 793 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 488 794 for (int i = 0; i < 5; i++) 489 ImGui::Text("Some content %d", i);490 491 492 493 ImGui::Text("IsItemHovered: %d", I sItemHovered());795 ImGui::Text("Some content %d", i); 796 } 797 if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) 798 { 799 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 494 800 for (int i = 0; i < 5; i++) 495 ImGui::Text("More content %d", i); 496 } 497 ImGui::TreePop(); 498 } 499 500 if (ImGui::TreeNode("Bullets")) 501 { 502 ImGui::BulletText("Bullet point 1"); 503 ImGui::BulletText("Bullet point 2\nOn multiple lines"); 504 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); 505 ImGui::Bullet(); ImGui::SmallButton("Button"); 506 ImGui::TreePop(); 507 } 508 509 if (ImGui::TreeNode("Text")) 510 { 511 if (ImGui::TreeNode("Colored Text")) 512 { 801 ImGui::Text("More content %d", i); 802 } 803 /* 804 if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) 805 ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); 806 */ 807 ImGui::TreePop(); 808 } 809 810 if (ImGui::TreeNode("Bullets")) 811 { 812 ImGui::BulletText("Bullet point 1"); 813 ImGui::BulletText("Bullet point 2\nOn multiple lines"); 814 if (ImGui::TreeNode("Tree node")) 815 { 816 ImGui::BulletText("Another bullet point"); 817 ImGui::TreePop(); 818 } 819 ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); 820 ImGui::Bullet(); ImGui::SmallButton("Button"); 821 ImGui::TreePop(); 822 } 823 824 if (ImGui::TreeNode("Text")) 825 { 826 if (ImGui::TreeNode("Colored Text")) 827 { 513 828 // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. 514 829 ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); 515 830 ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); 516 831 ImGui::TextDisabled("Disabled"); 517 ImGui::SameLine(); ShowHelpMarker("The TextDisabled color is stored in ImGuiStyle.");832 ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); 518 833 ImGui::TreePop(); 519 520 521 522 834 } 835 836 if (ImGui::TreeNode("Word Wrapping")) 837 { 523 838 // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. 524 ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages."); 839 ImGui::TextWrapped( 840 "This text should automatically wrap on the edge of the window. The current implementation " 841 "for text wrapping follows simple rules suitable for English and possibly other languages."); 525 842 ImGui::Spacing(); 526 843 … … 528 845 ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); 529 846 530 ImGui::Text("Test paragraph 1:"); 531 ImVec2 pos = ImGui::GetCursorScreenPos(); 532 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255, 0, 255, 255)); 533 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 534 ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); 535 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); 536 ImGui::PopTextWrapPos(); 537 538 ImGui::Text("Test paragraph 2:"); 539 pos = ImGui::GetCursorScreenPos(); 540 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255, 0, 255, 255)); 541 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 542 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); 543 ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); 544 ImGui::PopTextWrapPos(); 847 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 848 for (int n = 0; n < 2; n++) 849 { 850 ImGui::Text("Test paragraph %d:", n); 851 ImVec2 pos = ImGui::GetCursorScreenPos(); 852 ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); 853 ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); 854 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); 855 if (n == 0) 856 ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); 857 else 858 ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); 859 860 // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) 861 draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); 862 draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); 863 ImGui::PopTextWrapPos(); 864 } 545 865 546 866 ImGui::TreePop(); 547 548 549 550 867 } 868 869 if (ImGui::TreeNode("UTF-8 Text")) 870 { 551 871 // UTF-8 test with Japanese characters 552 // ( needs a suitable font, try Arial Unicode or M+ fonts http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html)872 // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) 553 873 // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 554 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature') 555 // - HOWEVER, FOR THIS DEMO FILE, BECAUSE WE WANT TO SUPPORT COMPILER, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE. 556 // Instead we are encoding a few string with hexadecimal constants. Don't do this in your application! 557 // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application. 558 ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to load extra character ranges."); 559 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); 874 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you 875 // can save your source files as 'UTF-8 without signature'). 876 // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 877 // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. 878 // Don't do this in your application! Please use u8"text in any language" in your application! 879 // Note that characters values are preserved even by InputText() if the font cannot be displayed, 880 // so you can safely copy & paste garbled characters into another application. 881 ImGui::TextWrapped( 882 "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. " 883 "Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. " 884 "Read docs/FONTS.md for details."); 885 ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. 560 886 ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); 561 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; // "nihongo" 887 static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; 888 //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis 562 889 ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); 563 890 ImGui::TreePop(); 564 } 565 ImGui::TreePop(); 566 } 567 568 if (ImGui::TreeNode("Images")) 569 { 570 ImGuiIO& io = ImGui::GetIO(); 571 ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!"); 572 573 // Here we are grabbing the font texture because that's the only one we have access to inside the demo code. 574 // Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure. 575 // If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID. 576 // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_glfw_gl3.cpp renderer expect a GLuint OpenGL texture identifier etc.) 577 // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc. 578 // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this. 579 // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). 580 ImTextureID my_tex_id = io.Fonts->TexID; 581 float my_tex_w = (float)io.Fonts->TexWidth; 582 float my_tex_h = (float)io.Fonts->TexHeight; 583 584 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); 585 ImVec2 pos = ImGui::GetCursorScreenPos(); 586 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); 587 if (ImGui::IsItemHovered()) 588 { 589 ImGui::BeginTooltip(); 590 float region_sz = 32.0f; 591 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; if (region_x < 0.0f) region_x = 0.0f; else if (region_x > my_tex_w - region_sz) region_x = my_tex_w - region_sz; 592 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; if (region_y < 0.0f) region_y = 0.0f; else if (region_y > my_tex_h - region_sz) region_y = my_tex_h - region_sz; 593 float zoom = 4.0f; 594 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); 595 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); 596 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); 597 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); 598 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); 599 ImGui::EndTooltip(); 600 } 601 ImGui::TextWrapped("And now some textured buttons.."); 602 static int pressed_count = 0; 603 for (int i = 0; i < 8; i++) 604 { 891 } 892 ImGui::TreePop(); 893 } 894 895 if (ImGui::TreeNode("Images")) 896 { 897 ImGuiIO& io = ImGui::GetIO(); 898 ImGui::TextWrapped( 899 "Below we are displaying the font texture (which is the only texture we have access to in this demo). " 900 "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " 901 "Hover the texture for a zoomed view!"); 902 903 // Below we are displaying the font texture because it is the only texture we have access to inside the demo! 904 // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that 905 // will be passed to the rendering back-end via the ImDrawCmd structure. 906 // If you use one of the default imgui_impl_XXXX.cpp rendering back-end, they all have comments at the top 907 // of their respective source file to specify what they expect to be stored in ImTextureID, for example: 908 // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer 909 // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. 910 // More: 911 // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers 912 // to ImGui::Image(), and gather width/height through your own functions, etc. 913 // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, 914 // it will help you debug issues if you are confused about it. 915 // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). 916 // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md 917 // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples 918 ImTextureID my_tex_id = io.Fonts->TexID; 919 float my_tex_w = (float)io.Fonts->TexWidth; 920 float my_tex_h = (float)io.Fonts->TexHeight; 921 { 922 ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); 923 ImVec2 pos = ImGui::GetCursorScreenPos(); 924 ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left 925 ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right 926 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint 927 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white 928 ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); 929 if (ImGui::IsItemHovered()) 930 { 931 ImGui::BeginTooltip(); 932 float region_sz = 32.0f; 933 float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; 934 float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; 935 float zoom = 4.0f; 936 if (region_x < 0.0f) { region_x = 0.0f; } 937 else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } 938 if (region_y < 0.0f) { region_y = 0.0f; } 939 else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } 940 ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); 941 ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); 942 ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); 943 ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); 944 ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col); 945 ImGui::EndTooltip(); 946 } 947 } 948 ImGui::TextWrapped("And now some textured buttons.."); 949 static int pressed_count = 0; 950 for (int i = 0; i < 8; i++) 951 { 605 952 ImGui::PushID(i); 606 int frame_padding = -1 + i; // -1 = uses default padding 607 if (ImGui::ImageButton(my_tex_id, ImVec2(32, 32), ImVec2(0, 0), ImVec2(32.0f / my_tex_w, 32 / my_tex_h), frame_padding, ImColor(0, 0, 0, 255))) 608 pressed_count += 1; 953 int frame_padding = -1 + i; // -1 == uses default padding (style.FramePadding) 954 ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible 955 ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left 956 ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);// UV coordinates for (32,32) in our texture 957 ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background 958 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint 959 if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col)) 960 pressed_count += 1; 609 961 ImGui::PopID(); 610 962 ImGui::SameLine(); 611 } 612 ImGui::NewLine(); 613 ImGui::Text("Pressed %d times.", pressed_count); 614 ImGui::TreePop(); 615 } 616 617 if (ImGui::TreeNode("Combo")) 618 { 619 // Expose flags as checkbox for the demo 620 static ImGuiComboFlags flags = 0; 621 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); 622 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) 963 } 964 ImGui::NewLine(); 965 ImGui::Text("Pressed %d times.", pressed_count); 966 ImGui::TreePop(); 967 } 968 969 if (ImGui::TreeNode("Combo")) 970 { 971 // Expose flags as checkbox for the demo 972 static ImGuiComboFlags flags = 0; 973 ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); 974 ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); 975 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) 623 976 flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both 624 977 if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) 625 978 flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both 626 979 627 // General BeginCombo() API, you have full control over your selection data and display type. 628 // (your selection data could be an index, a pointer to the object, an id for the object, a flag stored in the object itself, etc.) 629 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 630 static const char* item_current = items[0]; // Here our selection is a single pointer stored outside the object. 631 if (ImGui::BeginCombo("combo 1", item_current, flags)) // The second parameter is the label previewed before opening the combo. 632 { 980 // Using the generic BeginCombo() API, you have full control over how to display the combo contents. 981 // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively 982 // stored in the object itself, etc.) 983 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; 984 static int item_current_idx = 0; // Here our selection data is an index. 985 const char* combo_label = items[item_current_idx]; // Label to preview before opening the combo (technically it could be anything) 986 if (ImGui::BeginCombo("combo 1", combo_label, flags)) 987 { 633 988 for (int n = 0; n < IM_ARRAYSIZE(items); n++) 634 989 { 635 bool is_selected = (item_current == items[n]); 636 if (ImGui::Selectable(items[n], is_selected)) 637 item_current = items[n]; 638 if (is_selected) 639 ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch) 990 const bool is_selected = (item_current_idx == n); 991 if (ImGui::Selectable(items[n], is_selected)) 992 item_current_idx = n; 993 994 // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) 995 if (is_selected) 996 ImGui::SetItemDefaultFocus(); 640 997 } 641 998 ImGui::EndCombo(); 642 } 643 644 // Simplified one-liner Combo() API, using values packed in a single constant string 645 static int item_current_2 = 0; 646 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 647 648 // Simplified one-liner Combo() using an array of const char* 649 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview 650 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); 651 652 // Simplified one-liner Combo() using an accessor function 653 struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } }; 654 static int item_current_4 = 0; 655 ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items)); 656 657 ImGui::TreePop(); 658 } 659 660 if (ImGui::TreeNode("Selectables")) 661 { 662 // Selectable() has 2 overloads: 663 // - The one taking "bool selected" as a read-only selection information. When Selectable() has been clicked is returns true and you can alter selection state accordingly. 664 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) 665 // The earlier is more flexible, as in real application your selection may be stored in a different manner (in flags within objects, as an external list, etc). 666 if (ImGui::TreeNode("Basic")) 667 { 999 } 1000 1001 // Simplified one-liner Combo() API, using values packed in a single constant string 1002 static int item_current_2 = 0; 1003 ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 1004 1005 // Simplified one-liner Combo() using an array of const char* 1006 static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview 1007 ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); 1008 1009 // Simplified one-liner Combo() using an accessor function 1010 struct Funcs { static bool ItemGetter(void* data, int n, const char** out_str) { *out_str = ((const char**)data)[n]; return true; } }; 1011 static int item_current_4 = 0; 1012 ImGui::Combo("combo 4 (function)", &item_current_4, &Funcs::ItemGetter, items, IM_ARRAYSIZE(items)); 1013 1014 ImGui::TreePop(); 1015 } 1016 1017 if (ImGui::TreeNode("Selectables")) 1018 { 1019 // Selectable() has 2 overloads: 1020 // - The one taking "bool selected" as a read-only selection information. 1021 // When Selectable() has been clicked it returns true and you can alter selection state accordingly. 1022 // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) 1023 // The earlier is more flexible, as in real application your selection may be stored in many different ways 1024 // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). 1025 if (ImGui::TreeNode("Basic")) 1026 { 668 1027 static bool selection[5] = { false, true, false, false, false }; 669 1028 ImGui::Selectable("1. I am selectable", &selection[0]); … … 672 1031 ImGui::Selectable("4. I am selectable", &selection[3]); 673 1032 if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick)) 674 if (ImGui::IsMouseDoubleClicked(0))675 selection[4] = !selection[4];1033 if (ImGui::IsMouseDoubleClicked(0)) 1034 selection[4] = !selection[4]; 676 1035 ImGui::TreePop(); 677 678 679 1036 } 1037 if (ImGui::TreeNode("Selection State: Single Selection")) 1038 { 680 1039 static int selected = -1; 681 1040 for (int n = 0; n < 5; n++) 682 1041 { 683 char buf[32];684 sprintf(buf, "Object %d", n);685 if (ImGui::Selectable(buf, selected == n))686 selected = n;1042 char buf[32]; 1043 sprintf(buf, "Object %d", n); 1044 if (ImGui::Selectable(buf, selected == n)) 1045 selected = n; 687 1046 } 688 1047 ImGui::TreePop(); 689 690 691 692 ShowHelpMarker("Hold CTRL and click to select multiple items.");1048 } 1049 if (ImGui::TreeNode("Selection State: Multiple Selection")) 1050 { 1051 HelpMarker("Hold CTRL and click to select multiple items."); 693 1052 static bool selection[5] = { false, false, false, false, false }; 694 1053 for (int n = 0; n < 5; n++) 695 1054 { 696 char buf[32];697 sprintf(buf, "Object %d", n);698 if (ImGui::Selectable(buf, selection[n]))699 {700 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held701 memset(selection, 0, sizeof(selection));702 selection[n] ^= 1;703 }1055 char buf[32]; 1056 sprintf(buf, "Object %d", n); 1057 if (ImGui::Selectable(buf, selection[n])) 1058 { 1059 if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held 1060 memset(selection, 0, sizeof(selection)); 1061 selection[n] ^= 1; 1062 } 704 1063 } 705 1064 ImGui::TreePop(); 706 } 707 if (ImGui::TreeNode("Rendering more text into the same line")) 708 { 709 // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically. 1065 } 1066 if (ImGui::TreeNode("Rendering more text into the same line")) 1067 { 1068 // Using the Selectable() override that takes "bool* p_selected" parameter, 1069 // this function toggle your bool value automatically. 710 1070 static bool selected[3] = { false, false, false }; 711 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");1071 ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 712 1072 ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes"); 713 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");1073 ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes"); 714 1074 ImGui::TreePop(); 715 716 717 1075 } 1076 if (ImGui::TreeNode("In columns")) 1077 { 718 1078 ImGui::Columns(3, NULL, false); 719 static bool selected[16] = { 0};1079 static bool selected[16] = {}; 720 1080 for (int i = 0; i < 16; i++) 721 1081 { 722 char label[32]; sprintf(label, "Item %d", i);723 if (ImGui::Selectable(label, &selected[i])) {}724 ImGui::NextColumn();1082 char label[32]; sprintf(label, "Item %d", i); 1083 if (ImGui::Selectable(label, &selected[i])) {} 1084 ImGui::NextColumn(); 725 1085 } 726 1086 ImGui::Columns(1); 727 1087 ImGui::TreePop(); 728 } 729 if (ImGui::TreeNode("Grid")) 730 { 731 static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true }; 732 for (int i = 0; i < 16; i++) 733 { 734 ImGui::PushID(i); 735 if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50, 50))) 736 { 737 int x = i % 4, y = i / 4; 738 if (x > 0) selected[i - 1] ^= 1; 739 if (x < 3) selected[i + 1] ^= 1; 740 if (y > 0) selected[i - 4] ^= 1; 741 if (y < 3) selected[i + 4] ^= 1; 742 } 743 if ((i % 4) < 3) ImGui::SameLine(); 744 ImGui::PopID(); 745 } 1088 } 1089 if (ImGui::TreeNode("Grid")) 1090 { 1091 static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; 1092 1093 // Add in a bit of silly fun... 1094 const float time = (float)ImGui::GetTime(); 1095 const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... 1096 if (winning_state) 1097 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); 1098 1099 for (int y = 0; y < 4; y++) 1100 for (int x = 0; x < 4; x++) 1101 { 1102 if (x > 0) 1103 ImGui::SameLine(); 1104 ImGui::PushID(y * 4 + x); 1105 if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) 1106 { 1107 // Toggle clicked cell + toggle neighbors 1108 selected[y][x] ^= 1; 1109 if (x > 0) { selected[y][x - 1] ^= 1; } 1110 if (x < 3) { selected[y][x + 1] ^= 1; } 1111 if (y > 0) { selected[y - 1][x] ^= 1; } 1112 if (y < 3) { selected[y + 1][x] ^= 1; } 1113 } 1114 ImGui::PopID(); 1115 } 1116 1117 if (winning_state) 1118 ImGui::PopStyleVar(); 746 1119 ImGui::TreePop(); 747 } 748 ImGui::TreePop(); 749 } 750 751 if (ImGui::TreeNode("Filtered Text Input")) 752 { 753 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); 754 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); 755 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); 756 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); 757 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); 758 struct TextFilters { static int FilterImGuiLetters(ImGuiTextEditCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } }; 759 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); 760 761 ImGui::Text("Password input"); 762 static char bufpass[64] = "password123"; 763 ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank); 764 ImGui::SameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); 765 ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank); 766 767 ImGui::TreePop(); 768 } 769 770 if (ImGui::TreeNode("Multi-line Text Input")) 771 { 772 static bool read_only = false; 773 static char text[1024 * 16] = 774 "/*\n" 775 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" 776 " the hexadecimal encoding of one offending instruction,\n" 777 " more formally, the invalid operand with locked CMPXCHG8B\n" 778 " instruction bug, is a design flaw in the majority of\n" 779 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" 780 " processors (all in the P5 microarchitecture).\n" 781 "*/\n\n" 782 "label:\n" 783 "\tlock cmpxchg8b eax\n"; 784 785 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 786 ImGui::Checkbox("Read-only", &read_only); 787 ImGui::PopStyleVar(); 788 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0)); 789 ImGui::TreePop(); 790 } 791 792 if (ImGui::TreeNode("Plots widgets")) 793 { 794 static bool animate = true; 795 ImGui::Checkbox("Animate", &animate); 796 797 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 798 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); 799 800 // Create a dummy array of contiguous float values to plot 801 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter. 802 static float values[90] = { 0 }; 803 static int values_offset = 0; 804 static float refresh_time = 0.0f; 805 if (!animate || refresh_time == 0.0f) 1120 } 1121 if (ImGui::TreeNode("Alignment")) 1122 { 1123 HelpMarker( 1124 "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " 1125 "basis using PushStyleVar(). You'll probably want to always keep your default situation to " 1126 "left-align otherwise it becomes difficult to layout multiple items on a same line"); 1127 static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; 1128 for (int y = 0; y < 3; y++) 1129 { 1130 for (int x = 0; x < 3; x++) 1131 { 1132 ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); 1133 char name[32]; 1134 sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); 1135 if (x > 0) ImGui::SameLine(); 1136 ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); 1137 ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); 1138 ImGui::PopStyleVar(); 1139 } 1140 } 1141 ImGui::TreePop(); 1142 } 1143 ImGui::TreePop(); 1144 } 1145 1146 // To wire InputText() with std::string or any other custom string type, 1147 // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. 1148 if (ImGui::TreeNode("Text Input")) 1149 { 1150 if (ImGui::TreeNode("Multi-line Text Input")) 1151 { 1152 // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize 1153 // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. 1154 static char text[1024 * 16] = 1155 "/*\n" 1156 " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" 1157 " the hexadecimal encoding of one offending instruction,\n" 1158 " more formally, the invalid operand with locked CMPXCHG8B\n" 1159 " instruction bug, is a design flaw in the majority of\n" 1160 " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" 1161 " processors (all in the P5 microarchitecture).\n" 1162 "*/\n\n" 1163 "label:\n" 1164 "\tlock cmpxchg8b eax\n"; 1165 1166 static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; 1167 HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include <string> in here)"); 1168 ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); 1169 ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); 1170 ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); 1171 ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); 1172 ImGui::TreePop(); 1173 } 1174 1175 if (ImGui::TreeNode("Filtered Text Input")) 1176 { 1177 struct TextFilters 1178 { 1179 // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i' 1180 static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) 1181 { 1182 if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) 1183 return 0; 1184 return 1; 1185 } 1186 }; 1187 1188 static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); 1189 static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal); 1190 static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); 1191 static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase); 1192 static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank); 1193 static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); 1194 ImGui::TreePop(); 1195 } 1196 1197 if (ImGui::TreeNode("Password Input")) 1198 { 1199 static char password[64] = "password123"; 1200 ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1201 ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); 1202 ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); 1203 ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); 1204 ImGui::TreePop(); 1205 } 1206 1207 if (ImGui::TreeNode("Completion, History, Edit Callbacks")) 1208 { 1209 struct Funcs 1210 { 1211 static int MyCallback(ImGuiInputTextCallbackData* data) 1212 { 1213 if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) 1214 { 1215 data->InsertChars(data->CursorPos, ".."); 1216 } 1217 else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) 1218 { 1219 if (data->EventKey == ImGuiKey_UpArrow) 1220 { 1221 data->DeleteChars(0, data->BufTextLen); 1222 data->InsertChars(0, "Pressed Up!"); 1223 data->SelectAll(); 1224 } 1225 else if (data->EventKey == ImGuiKey_DownArrow) 1226 { 1227 data->DeleteChars(0, data->BufTextLen); 1228 data->InsertChars(0, "Pressed Down!"); 1229 data->SelectAll(); 1230 } 1231 } 1232 else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) 1233 { 1234 // Toggle casing of first character 1235 char c = data->Buf[0]; 1236 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; 1237 data->BufDirty = true; 1238 1239 // Increment a counter 1240 int* p_int = (int*)data->UserData; 1241 *p_int = *p_int + 1; 1242 } 1243 return 0; 1244 } 1245 }; 1246 static char buf1[64]; 1247 ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); 1248 ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); 1249 1250 static char buf2[64]; 1251 ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); 1252 ImGui::SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback."); 1253 1254 static char buf3[64]; 1255 static int edit_count = 0; 1256 ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); 1257 ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits."); 1258 ImGui::SameLine(); ImGui::Text("(%d)", edit_count); 1259 1260 ImGui::TreePop(); 1261 } 1262 1263 if (ImGui::TreeNode("Resize Callback")) 1264 { 1265 // To wire InputText() with std::string or any other custom string type, 1266 // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper 1267 // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. 1268 HelpMarker( 1269 "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" 1270 "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); 1271 struct Funcs 1272 { 1273 static int MyResizeCallback(ImGuiInputTextCallbackData* data) 1274 { 1275 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) 1276 { 1277 ImVector<char>* my_str = (ImVector<char>*)data->UserData; 1278 IM_ASSERT(my_str->begin() == data->Buf); 1279 my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 1280 data->Buf = my_str->begin(); 1281 } 1282 return 0; 1283 } 1284 1285 // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. 1286 // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' 1287 static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) 1288 { 1289 IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 1290 return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); 1291 } 1292 }; 1293 1294 // For this demo we are using ImVector as a string container. 1295 // Note that because we need to store a terminating zero character, our size/capacity are 1 more 1296 // than usually reported by a typical string class. 1297 static ImVector<char> my_str; 1298 if (my_str.empty()) 1299 my_str.push_back(0); 1300 Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); 1301 ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); 1302 ImGui::TreePop(); 1303 } 1304 1305 ImGui::TreePop(); 1306 } 1307 1308 // Plot/Graph widgets are currently fairly limited. 1309 // Consider writing your own plotting widget, or using a third-party one 1310 // (for third-party Plot widgets, see 'Wiki->Useful Widgets' or https://github.com/ocornut/imgui/labels/plot%2Fgraph) 1311 if (ImGui::TreeNode("Plots Widgets")) 1312 { 1313 static bool animate = true; 1314 ImGui::Checkbox("Animate", &animate); 1315 1316 static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; 1317 ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); 1318 1319 // Fill an array of contiguous float values to plot 1320 // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float 1321 // and the sizeof() of your structure in the "stride" parameter. 1322 static float values[90] = {}; 1323 static int values_offset = 0; 1324 static double refresh_time = 0.0; 1325 if (!animate || refresh_time == 0.0) 806 1326 refresh_time = ImGui::GetTime(); 807 while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo808 1327 while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo 1328 { 809 1329 static float phase = 0.0f; 810 1330 values[values_offset] = cosf(phase); 811 1331 values_offset = (values_offset + 1) % IM_ARRAYSIZE(values); 812 phase += 0.10f *values_offset;1332 phase += 0.10f * values_offset; 813 1333 refresh_time += 1.0f / 60.0f; 814 } 815 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0, 80)); 816 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80)); 817 818 // Use functions to generate output 819 // FIXME: This is rather awkward because current plot API only pass in indices. We probably want an API passing floats and user provide sample rate/count. 820 struct Funcs 821 { 1334 } 1335 1336 // Plots can display overlay texts 1337 // (in this example, we will display an average value) 1338 { 1339 float average = 0.0f; 1340 for (int n = 0; n < IM_ARRAYSIZE(values); n++) 1341 average += values[n]; 1342 average /= (float)IM_ARRAYSIZE(values); 1343 char overlay[32]; 1344 sprintf(overlay, "avg %f", average); 1345 ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); 1346 } 1347 ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); 1348 1349 // Use functions to generate output 1350 // FIXME: This is rather awkward because current plot API only pass in indices. 1351 // We probably want an API passing floats and user provide sample rate/count. 1352 struct Funcs 1353 { 822 1354 static float Sin(void*, int i) { return sinf(i * 0.1f); } 823 1355 static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } 824 }; 825 static int func_type = 0, display_count = 70; 826 ImGui::Separator(); 827 ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth(); 828 ImGui::SameLine(); 829 ImGui::SliderInt("Sample count", &display_count, 1, 400); 830 float(*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; 831 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 832 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 833 ImGui::Separator(); 834 835 // Animate a simple progress bar 836 static float progress = 0.0f, progress_dir = 1.0f; 837 if (animate) 838 { 1356 }; 1357 static int func_type = 0, display_count = 70; 1358 ImGui::Separator(); 1359 ImGui::SetNextItemWidth(100); 1360 ImGui::Combo("func", &func_type, "Sin\0Saw\0"); 1361 ImGui::SameLine(); 1362 ImGui::SliderInt("Sample count", &display_count, 1, 400); 1363 float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; 1364 ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 1365 ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); 1366 ImGui::Separator(); 1367 1368 // Animate a simple progress bar 1369 static float progress = 0.0f, progress_dir = 1.0f; 1370 if (animate) 1371 { 839 1372 progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; 840 1373 if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } 841 1374 if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } 842 } 843 844 // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. 845 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); 846 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 847 ImGui::Text("Progress Bar"); 848 849 float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress; 850 char buf[32]; 851 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); 852 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); 853 ImGui::TreePop(); 854 } 855 856 if (ImGui::TreeNode("Color/Picker Widgets")) 857 { 858 static ImVec4 color = ImColor(114, 144, 154, 200); 859 860 static bool alpha_preview = true; 861 static bool alpha_half_preview = false; 862 static bool options_menu = true; 863 static bool hdr = false; 864 ImGui::Checkbox("With Alpha Preview", &alpha_preview); 865 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); 866 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); ShowHelpMarker("Right-click on the individual color widget to show options."); 867 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); ShowHelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); 868 int misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); 869 870 ImGui::Text("Color widget:"); 871 ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n"); 872 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); 873 874 ImGui::Text("Color widget HSV with Alpha:"); 875 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_HSV | misc_flags); 876 877 ImGui::Text("Color widget with Float Display:"); 878 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); 879 880 ImGui::Text("Color button with Picker:"); 881 ImGui::SameLine(); ShowHelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup."); 882 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); 883 884 ImGui::Text("Color button with Custom Picker Popup:"); 885 886 // Generate a dummy palette 887 static bool saved_palette_inited = false; 888 static ImVec4 saved_palette[32]; 889 if (!saved_palette_inited) 1375 } 1376 1377 // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, 1378 // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. 1379 ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); 1380 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 1381 ImGui::Text("Progress Bar"); 1382 1383 float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); 1384 char buf[32]; 1385 sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); 1386 ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); 1387 ImGui::TreePop(); 1388 } 1389 1390 if (ImGui::TreeNode("Color/Picker Widgets")) 1391 { 1392 static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); 1393 1394 static bool alpha_preview = true; 1395 static bool alpha_half_preview = false; 1396 static bool drag_and_drop = true; 1397 static bool options_menu = true; 1398 static bool hdr = false; 1399 ImGui::Checkbox("With Alpha Preview", &alpha_preview); 1400 ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); 1401 ImGui::Checkbox("With Drag and Drop", &drag_and_drop); 1402 ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); 1403 ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); 1404 ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); 1405 1406 ImGui::Text("Color widget:"); 1407 ImGui::SameLine(); HelpMarker( 1408 "Click on the colored square to open a color picker.\n" 1409 "CTRL+click on individual component to input value.\n"); 1410 ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); 1411 1412 ImGui::Text("Color widget HSV with Alpha:"); 1413 ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); 1414 1415 ImGui::Text("Color widget with Float Display:"); 1416 ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); 1417 1418 ImGui::Text("Color button with Picker:"); 1419 ImGui::SameLine(); HelpMarker( 1420 "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" 1421 "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " 1422 "be used for the tooltip and picker popup."); 1423 ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); 1424 1425 ImGui::Text("Color button with Custom Picker Popup:"); 1426 1427 // Generate a default palette. The palette will persist and can be edited. 1428 static bool saved_palette_init = true; 1429 static ImVec4 saved_palette[32] = {}; 1430 if (saved_palette_init) 1431 { 890 1432 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 891 1433 { 892 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); 893 saved_palette[n].w = 1.0f; // Alpha 894 } 895 saved_palette_inited = true; 896 897 static ImVec4 backup_color; 898 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); 899 ImGui::SameLine(); 900 open_popup |= ImGui::Button("Palette"); 901 if (open_popup) 902 { 1434 ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, 1435 saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); 1436 saved_palette[n].w = 1.0f; // Alpha 1437 } 1438 saved_palette_init = false; 1439 } 1440 1441 static ImVec4 backup_color; 1442 bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); 1443 ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); 1444 open_popup |= ImGui::Button("Palette"); 1445 if (open_popup) 1446 { 903 1447 ImGui::OpenPopup("mypicker"); 904 1448 backup_color = color; 905 } 906 if (ImGui::BeginPopup("mypicker")) 907 { 908 // FIXME: Adding a drag and drop example here would be perfect! 1449 } 1450 if (ImGui::BeginPopup("mypicker")) 1451 { 909 1452 ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); 910 1453 ImGui::Separator(); 911 1454 ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); 912 1455 ImGui::SameLine(); 913 ImGui::BeginGroup(); 1456 1457 ImGui::BeginGroup(); // Lock X position 914 1458 ImGui::Text("Current"); 915 1459 ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); 916 1460 ImGui::Text("Previous"); 917 1461 if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) 918 color = backup_color;1462 color = backup_color; 919 1463 ImGui::Separator(); 920 1464 ImGui::Text("Palette"); 921 1465 for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) 922 1466 { 923 ImGui::PushID(n); 924 if ((n % 8) != 0) 925 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); 926 if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20))) 927 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! 928 929 if (ImGui::BeginDragDropTarget()) 930 { 931 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) 932 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); 933 if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) 934 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); 935 EndDragDropTarget(); 936 } 937 938 ImGui::PopID(); 1467 ImGui::PushID(n); 1468 if ((n % 8) != 0) 1469 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); 1470 1471 ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; 1472 if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) 1473 color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! 1474 1475 // Allow user to drop colors into each palette entry. Note that ColorButton() is already a 1476 // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. 1477 if (ImGui::BeginDragDropTarget()) 1478 { 1479 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) 1480 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); 1481 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) 1482 memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); 1483 ImGui::EndDragDropTarget(); 1484 } 1485 1486 ImGui::PopID(); 939 1487 } 940 1488 ImGui::EndGroup(); 941 1489 ImGui::EndPopup(); 942 } 943 944 ImGui::Text("Color button only:"); 945 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags, ImVec2(80, 80)); 946 947 ImGui::Text("Color picker:"); 948 static bool alpha = true; 949 static bool alpha_bar = true; 950 static bool side_preview = true; 951 static bool ref_color = false; 952 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); 953 static int inputs_mode = 2; 954 static int picker_mode = 0; 955 ImGui::Checkbox("With Alpha", &alpha); 956 ImGui::Checkbox("With Alpha Bar", &alpha_bar); 957 ImGui::Checkbox("With Side Preview", &side_preview); 958 if (side_preview) 959 { 1490 } 1491 1492 ImGui::Text("Color button only:"); 1493 static bool no_border = false; 1494 ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); 1495 ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); 1496 1497 ImGui::Text("Color picker:"); 1498 static bool alpha = true; 1499 static bool alpha_bar = true; 1500 static bool side_preview = true; 1501 static bool ref_color = false; 1502 static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); 1503 static int display_mode = 0; 1504 static int picker_mode = 0; 1505 ImGui::Checkbox("With Alpha", &alpha); 1506 ImGui::Checkbox("With Alpha Bar", &alpha_bar); 1507 ImGui::Checkbox("With Side Preview", &side_preview); 1508 if (side_preview) 1509 { 960 1510 ImGui::SameLine(); 961 1511 ImGui::Checkbox("With Ref Color", &ref_color); 962 1512 if (ref_color) 963 1513 { 964 ImGui::SameLine(); 965 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); 966 } 967 } 968 ImGui::Combo("Inputs Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0"); 969 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); 970 ImGui::SameLine(); ShowHelpMarker("User can right-click the picker to change mode."); 971 ImGuiColorEditFlags flags = misc_flags; 972 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() 973 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; 974 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; 975 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; 976 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; 977 if (inputs_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; 978 if (inputs_mode == 2) flags |= ImGuiColorEditFlags_RGB; 979 if (inputs_mode == 3) flags |= ImGuiColorEditFlags_HSV; 980 if (inputs_mode == 4) flags |= ImGuiColorEditFlags_HEX; 981 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); 982 983 ImGui::Text("Programmatically set defaults/options:"); 984 ImGui::SameLine(); ShowHelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible."); 985 if (ImGui::Button("Uint8 + HSV")) 986 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_HSV); 987 ImGui::SameLine(); 988 if (ImGui::Button("Float + HDR")) 989 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_RGB); 990 991 ImGui::TreePop(); 992 } 993 994 if (ImGui::TreeNode("Range Widgets")) 995 { 996 static float begin = 10, end = 90; 997 static int begin_i = 100, end_i = 1000; 998 ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); 999 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %.0f units", "Max: %.0f units"); 1000 ImGui::TreePop(); 1001 } 1002 1003 if (ImGui::TreeNode("Multi-component Widgets")) 1004 { 1005 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 1006 static int vec4i[4] = { 1, 5, 100, 255 }; 1007 1008 ImGui::InputFloat2("input float2", vec4f); 1009 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); 1010 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); 1011 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); 1012 ImGui::InputInt2("input int2", vec4i); 1013 ImGui::SliderInt2("slider int2", vec4i, 0, 255); 1014 ImGui::Spacing(); 1015 1016 ImGui::InputFloat3("input float3", vec4f); 1017 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); 1018 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); 1019 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); 1020 ImGui::InputInt3("input int3", vec4i); 1021 ImGui::SliderInt3("slider int3", vec4i, 0, 255); 1022 ImGui::Spacing(); 1023 1024 ImGui::InputFloat4("input float4", vec4f); 1025 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); 1026 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); 1027 ImGui::InputInt4("input int4", vec4i); 1028 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); 1029 ImGui::SliderInt4("slider int4", vec4i, 0, 255); 1030 1031 ImGui::TreePop(); 1032 } 1033 1034 if (ImGui::TreeNode("Vertical Sliders")) 1035 { 1036 const float spacing = 4; 1037 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); 1038 1039 static int int_value = 0; 1040 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); 1041 ImGui::SameLine(); 1042 1043 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; 1044 ImGui::PushID("set1"); 1045 for (int i = 0; i < 7; i++) 1046 { 1514 ImGui::SameLine(); 1515 ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); 1516 } 1517 } 1518 ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); 1519 ImGui::SameLine(); HelpMarker( 1520 "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " 1521 "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex " 1522 "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); 1523 ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0"); 1524 ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode."); 1525 ImGuiColorEditFlags flags = misc_flags; 1526 if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() 1527 if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; 1528 if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; 1529 if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; 1530 if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; 1531 if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays 1532 if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode 1533 if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; 1534 if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; 1535 ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); 1536 1537 ImGui::Text("Set defaults in code:"); 1538 ImGui::SameLine(); HelpMarker( 1539 "SetColorEditOptions() is designed to allow you to set boot-time default.\n" 1540 "We don't have Push/Pop functions because you can force options on a per-widget basis if needed," 1541 "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid" 1542 "encouraging you to persistently save values that aren't forward-compatible."); 1543 if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) 1544 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); 1545 if (ImGui::Button("Default: Float + HDR + Hue Wheel")) 1546 ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); 1547 1548 // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) 1549 static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! 1550 ImGui::Spacing(); 1551 ImGui::Text("HSV encoded colors"); 1552 ImGui::SameLine(); HelpMarker( 1553 "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV" 1554 "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the" 1555 "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); 1556 ImGui::Text("Color widget with InputHSV:"); 1557 ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1558 ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); 1559 ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); 1560 1561 ImGui::TreePop(); 1562 } 1563 1564 if (ImGui::TreeNode("Drag/Slider Flags")) 1565 { 1566 // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! 1567 static ImGuiSliderFlags flags = ImGuiSliderFlags_None; 1568 ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", (unsigned int*)&flags, ImGuiSliderFlags_AlwaysClamp); 1569 ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click."); 1570 ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", (unsigned int*)&flags, ImGuiSliderFlags_Logarithmic); 1571 ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); 1572 ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", (unsigned int*)&flags, ImGuiSliderFlags_NoRoundToFormat); 1573 ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); 1574 ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", (unsigned int*)&flags, ImGuiSliderFlags_NoInput); 1575 ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); 1576 1577 // Drags 1578 static float drag_f = 0.5f; 1579 static int drag_i = 50; 1580 ImGui::Text("Underlying float value: %f", drag_f); 1581 ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); 1582 ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); 1583 ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); 1584 ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); 1585 ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); 1586 1587 // Sliders 1588 static float slider_f = 0.5f; 1589 static int slider_i = 50; 1590 ImGui::Text("Underlying float value: %f", slider_f); 1591 ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags); 1592 ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags); 1593 1594 ImGui::TreePop(); 1595 } 1596 1597 if (ImGui::TreeNode("Range Widgets")) 1598 { 1599 static float begin = 10, end = 90; 1600 static int begin_i = 100, end_i = 1000; 1601 ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); 1602 ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); 1603 ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); 1604 ImGui::TreePop(); 1605 } 1606 1607 if (ImGui::TreeNode("Data Types")) 1608 { 1609 // DragScalar/InputScalar/SliderScalar functions allow various data types 1610 // - signed/unsigned 1611 // - 8/16/32/64-bits 1612 // - integer/float/double 1613 // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum 1614 // to pass the type, and passing all arguments by pointer. 1615 // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types. 1616 // In practice, if you frequently use a given type that is not covered by the normal API entry points, 1617 // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, 1618 // and then pass their address to the generic function. For example: 1619 // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") 1620 // { 1621 // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); 1622 // } 1623 1624 // Setup limits (as helper variables so we can take their address, as explained above) 1625 // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. 1626 #ifndef LLONG_MIN 1627 ImS64 LLONG_MIN = -9223372036854775807LL - 1; 1628 ImS64 LLONG_MAX = 9223372036854775807LL; 1629 ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); 1630 #endif 1631 const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; 1632 const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; 1633 const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; 1634 const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; 1635 const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; 1636 const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; 1637 const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; 1638 const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; 1639 const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; 1640 const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; 1641 1642 // State 1643 static char s8_v = 127; 1644 static ImU8 u8_v = 255; 1645 static short s16_v = 32767; 1646 static ImU16 u16_v = 65535; 1647 static ImS32 s32_v = -1; 1648 static ImU32 u32_v = (ImU32)-1; 1649 static ImS64 s64_v = -1; 1650 static ImU64 u64_v = (ImU64)-1; 1651 static float f32_v = 0.123f; 1652 static double f64_v = 90000.01234567890123456789; 1653 1654 const float drag_speed = 0.2f; 1655 static bool drag_clamp = false; 1656 ImGui::Text("Drags:"); 1657 ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); 1658 ImGui::SameLine(); HelpMarker( 1659 "As with every widgets in dear imgui, we never modify values unless there is a user interaction.\n" 1660 "You can override the clamping limits by using CTRL+Click to input a value."); 1661 ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); 1662 ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); 1663 ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); 1664 ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); 1665 ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); 1666 ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); 1667 ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); 1668 ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); 1669 ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); 1670 ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); 1671 ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); 1672 ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); 1673 1674 ImGui::Text("Sliders"); 1675 ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); 1676 ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); 1677 ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); 1678 ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); 1679 ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); 1680 ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); 1681 ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); 1682 ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); 1683 ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); 1684 ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); 1685 ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%I64d"); 1686 ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%I64d"); 1687 ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%I64d"); 1688 ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%I64u ms"); 1689 ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms"); 1690 ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%I64u ms"); 1691 ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); 1692 ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); 1693 ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); 1694 ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); 1695 ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); 1696 ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); 1697 1698 ImGui::Text("Sliders (reverse)"); 1699 ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); 1700 ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); 1701 ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); 1702 ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); 1703 ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%I64d"); 1704 ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%I64u ms"); 1705 1706 static bool inputs_step = true; 1707 ImGui::Text("Inputs"); 1708 ImGui::Checkbox("Show step buttons", &inputs_step); 1709 ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); 1710 ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); 1711 ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d"); 1712 ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u"); 1713 ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d"); 1714 ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1715 ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u"); 1716 ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal); 1717 ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL); 1718 ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL); 1719 ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL); 1720 ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL); 1721 1722 ImGui::TreePop(); 1723 } 1724 1725 if (ImGui::TreeNode("Multi-component Widgets")) 1726 { 1727 static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; 1728 static int vec4i[4] = { 1, 5, 100, 255 }; 1729 1730 ImGui::InputFloat2("input float2", vec4f); 1731 ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); 1732 ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); 1733 ImGui::InputInt2("input int2", vec4i); 1734 ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); 1735 ImGui::SliderInt2("slider int2", vec4i, 0, 255); 1736 ImGui::Spacing(); 1737 1738 ImGui::InputFloat3("input float3", vec4f); 1739 ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); 1740 ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); 1741 ImGui::InputInt3("input int3", vec4i); 1742 ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); 1743 ImGui::SliderInt3("slider int3", vec4i, 0, 255); 1744 ImGui::Spacing(); 1745 1746 ImGui::InputFloat4("input float4", vec4f); 1747 ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); 1748 ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); 1749 ImGui::InputInt4("input int4", vec4i); 1750 ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); 1751 ImGui::SliderInt4("slider int4", vec4i, 0, 255); 1752 1753 ImGui::TreePop(); 1754 } 1755 1756 if (ImGui::TreeNode("Vertical Sliders")) 1757 { 1758 const float spacing = 4; 1759 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); 1760 1761 static int int_value = 0; 1762 ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); 1763 ImGui::SameLine(); 1764 1765 static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; 1766 ImGui::PushID("set1"); 1767 for (int i = 0; i < 7; i++) 1768 { 1047 1769 if (i > 0) ImGui::SameLine(); 1048 1770 ImGui::PushID(i); … … 1053 1775 ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); 1054 1776 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 1055 ImGui::SetTooltip("%.3f", values[i]);1777 ImGui::SetTooltip("%.3f", values[i]); 1056 1778 ImGui::PopStyleColor(4); 1057 1779 ImGui::PopID(); 1058 1059 1060 1061 1062 1063 1064 1065 const ImVec2 small_slider_size(18, (160.0f - (rows - 1)*spacing) / rows);1066 1067 1780 } 1781 ImGui::PopID(); 1782 1783 ImGui::SameLine(); 1784 ImGui::PushID("set2"); 1785 static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; 1786 const int rows = 3; 1787 const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); 1788 for (int nx = 0; nx < 4; nx++) 1789 { 1068 1790 if (nx > 0) ImGui::SameLine(); 1069 1791 ImGui::BeginGroup(); 1070 1792 for (int ny = 0; ny < rows; ny++) 1071 1793 { 1072 ImGui::PushID(nx*rows + ny);1073 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");1074 if (ImGui::IsItemActive() || ImGui::IsItemHovered())1075 ImGui::SetTooltip("%.3f", values2[nx]);1076 ImGui::PopID();1794 ImGui::PushID(nx * rows + ny); 1795 ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); 1796 if (ImGui::IsItemActive() || ImGui::IsItemHovered()) 1797 ImGui::SetTooltip("%.3f", values2[nx]); 1798 ImGui::PopID(); 1077 1799 } 1078 1800 ImGui::EndGroup(); 1079 1080 1081 1082 1083 1084 1085 1801 } 1802 ImGui::PopID(); 1803 1804 ImGui::SameLine(); 1805 ImGui::PushID("set3"); 1806 for (int i = 0; i < 4; i++) 1807 { 1086 1808 if (i > 0) ImGui::SameLine(); 1087 1809 ImGui::PushID(i); … … 1090 1812 ImGui::PopStyleVar(); 1091 1813 ImGui::PopID(); 1092 } 1093 ImGui::PopID(); 1094 ImGui::PopStyleVar(); 1095 ImGui::TreePop(); 1096 } 1097 } 1098 1099 if (ImGui::CollapsingHeader("Layout")) 1100 { 1101 if (ImGui::TreeNode("Child regions")) 1102 { 1103 static bool disable_mouse_wheel = false; 1104 static bool disable_menu = false; 1105 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); 1106 ImGui::Checkbox("Disable Menu", &disable_menu); 1107 1108 static int line = 50; 1109 bool goto_line = ImGui::Button("Goto"); 1110 ImGui::SameLine(); 1111 ImGui::PushItemWidth(100); 1112 goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); 1113 ImGui::PopItemWidth(); 1114 1115 // Child 1: no border, enable horizontal scrollbar 1116 { 1117 ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 300), false, ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0)); 1814 } 1815 ImGui::PopID(); 1816 ImGui::PopStyleVar(); 1817 ImGui::TreePop(); 1818 } 1819 1820 if (ImGui::TreeNode("Drag and Drop")) 1821 { 1822 if (ImGui::TreeNode("Drag and drop in standard widgets")) 1823 { 1824 // ColorEdit widgets automatically act as drag source and drag target. 1825 // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F 1826 // to allow your own widgets to use colors in their drag and drop interaction. 1827 // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. 1828 HelpMarker("You can drag from the colored squares."); 1829 static float col1[3] = { 1.0f, 0.0f, 0.2f }; 1830 static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 1831 ImGui::ColorEdit3("color 1", col1); 1832 ImGui::ColorEdit4("color 2", col2); 1833 ImGui::TreePop(); 1834 } 1835 1836 if (ImGui::TreeNode("Drag and drop to copy/swap items")) 1837 { 1838 enum Mode 1839 { 1840 Mode_Copy, 1841 Mode_Move, 1842 Mode_Swap 1843 }; 1844 static int mode = 0; 1845 if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); 1846 if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); 1847 if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } 1848 static const char* names[9] = 1849 { 1850 "Bobby", "Beatrice", "Betty", 1851 "Brianna", "Barry", "Bernard", 1852 "Bibi", "Blaine", "Bryn" 1853 }; 1854 for (int n = 0; n < IM_ARRAYSIZE(names); n++) 1855 { 1856 ImGui::PushID(n); 1857 if ((n % 3) != 0) 1858 ImGui::SameLine(); 1859 ImGui::Button(names[n], ImVec2(60, 60)); 1860 1861 // Our buttons are both drag sources and drag targets here! 1862 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) 1863 { 1864 // Set payload to carry the index of our item (could be anything) 1865 ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); 1866 1867 // Display preview (could be anything, e.g. when dragging an image we could decide to display 1868 // the filename and a small preview of the image, etc.) 1869 if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } 1870 if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } 1871 if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } 1872 ImGui::EndDragDropSource(); 1873 } 1874 if (ImGui::BeginDragDropTarget()) 1875 { 1876 if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) 1877 { 1878 IM_ASSERT(payload->DataSize == sizeof(int)); 1879 int payload_n = *(const int*)payload->Data; 1880 if (mode == Mode_Copy) 1881 { 1882 names[n] = names[payload_n]; 1883 } 1884 if (mode == Mode_Move) 1885 { 1886 names[n] = names[payload_n]; 1887 names[payload_n] = ""; 1888 } 1889 if (mode == Mode_Swap) 1890 { 1891 const char* tmp = names[n]; 1892 names[n] = names[payload_n]; 1893 names[payload_n] = tmp; 1894 } 1895 } 1896 ImGui::EndDragDropTarget(); 1897 } 1898 ImGui::PopID(); 1899 } 1900 ImGui::TreePop(); 1901 } 1902 1903 if (ImGui::TreeNode("Drag to reorder items (simple)")) 1904 { 1905 // Simple reordering 1906 HelpMarker( 1907 "We don't use the drag and drop api at all here! " 1908 "Instead we query when the item is held but not hovered, and order items accordingly."); 1909 static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; 1910 for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) 1911 { 1912 const char* item = item_names[n]; 1913 ImGui::Selectable(item); 1914 1915 if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) 1916 { 1917 int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); 1918 if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) 1919 { 1920 item_names[n] = item_names[n_next]; 1921 item_names[n_next] = item; 1922 ImGui::ResetMouseDragDelta(); 1923 } 1924 } 1925 } 1926 ImGui::TreePop(); 1927 } 1928 1929 ImGui::TreePop(); 1930 } 1931 1932 if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)")) 1933 { 1934 // Select an item type 1935 const char* item_names[] = 1936 { 1937 "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat", 1938 "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "ListBox" 1939 }; 1940 static int item_type = 1; 1941 ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); 1942 ImGui::SameLine(); 1943 HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions."); 1944 1945 // Submit selected item item so we can query their status in the code following it. 1946 bool ret = false; 1947 static bool b = false; 1948 static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; 1949 static char str[16] = {}; 1950 if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction 1951 if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button 1952 if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater) 1953 if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox 1954 if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item 1955 if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) 1956 if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input 1957 if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 1958 if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) 1959 if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) 1960 if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node 1961 if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. 1962 if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } 1963 1964 // Display the values of IsItemHovered() and other common item state functions. 1965 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 1966 // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, 1967 // we query every state in a single call to avoid storing them and to simplify the code. 1968 ImGui::BulletText( 1969 "Return value = %d\n" 1970 "IsItemFocused() = %d\n" 1971 "IsItemHovered() = %d\n" 1972 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" 1973 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1974 "IsItemHovered(_AllowWhenOverlapped) = %d\n" 1975 "IsItemHovered(_RectOnly) = %d\n" 1976 "IsItemActive() = %d\n" 1977 "IsItemEdited() = %d\n" 1978 "IsItemActivated() = %d\n" 1979 "IsItemDeactivated() = %d\n" 1980 "IsItemDeactivatedAfterEdit() = %d\n" 1981 "IsItemVisible() = %d\n" 1982 "IsItemClicked() = %d\n" 1983 "IsItemToggledOpen() = %d\n" 1984 "GetItemRectMin() = (%.1f, %.1f)\n" 1985 "GetItemRectMax() = (%.1f, %.1f)\n" 1986 "GetItemRectSize() = (%.1f, %.1f)", 1987 ret, 1988 ImGui::IsItemFocused(), 1989 ImGui::IsItemHovered(), 1990 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 1991 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 1992 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), 1993 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), 1994 ImGui::IsItemActive(), 1995 ImGui::IsItemEdited(), 1996 ImGui::IsItemActivated(), 1997 ImGui::IsItemDeactivated(), 1998 ImGui::IsItemDeactivatedAfterEdit(), 1999 ImGui::IsItemVisible(), 2000 ImGui::IsItemClicked(), 2001 ImGui::IsItemToggledOpen(), 2002 ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, 2003 ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, 2004 ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y 2005 ); 2006 2007 static bool embed_all_inside_a_child_window = false; 2008 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); 2009 if (embed_all_inside_a_child_window) 2010 ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); 2011 2012 // Testing IsWindowFocused() function with its various flags. 2013 // Note that the ImGuiFocusedFlags_XXX flags can be combined. 2014 ImGui::BulletText( 2015 "IsWindowFocused() = %d\n" 2016 "IsWindowFocused(_ChildWindows) = %d\n" 2017 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" 2018 "IsWindowFocused(_RootWindow) = %d\n" 2019 "IsWindowFocused(_AnyWindow) = %d\n", 2020 ImGui::IsWindowFocused(), 2021 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), 2022 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), 2023 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), 2024 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); 2025 2026 // Testing IsWindowHovered() function with its various flags. 2027 // Note that the ImGuiHoveredFlags_XXX flags can be combined. 2028 ImGui::BulletText( 2029 "IsWindowHovered() = %d\n" 2030 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" 2031 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" 2032 "IsWindowHovered(_ChildWindows) = %d\n" 2033 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" 2034 "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" 2035 "IsWindowHovered(_RootWindow) = %d\n" 2036 "IsWindowHovered(_AnyWindow) = %d\n", 2037 ImGui::IsWindowHovered(), 2038 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2039 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 2040 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), 2041 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), 2042 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2043 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), 2044 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); 2045 2046 ImGui::BeginChild("child", ImVec2(0, 50), true); 2047 ImGui::Text("This is another child window for testing the _ChildWindows flag."); 2048 ImGui::EndChild(); 2049 if (embed_all_inside_a_child_window) 2050 ImGui::EndChild(); 2051 2052 static char unused_str[] = "This widget is only here to be able to tab-out of the widgets above."; 2053 ImGui::InputText("unused", unused_str, IM_ARRAYSIZE(unused_str), ImGuiInputTextFlags_ReadOnly); 2054 2055 // Calling IsItemHovered() after begin returns the hovered status of the title bar. 2056 // This is useful in particular if you want to create a context menu associated to the title bar of a window. 2057 static bool test_window = false; 2058 ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); 2059 if (test_window) 2060 { 2061 ImGui::Begin("Title bar Hovered/Active tests", &test_window); 2062 if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() 2063 { 2064 if (ImGui::MenuItem("Close")) { test_window = false; } 2065 ImGui::EndPopup(); 2066 } 2067 ImGui::Text( 2068 "IsItemHovered() after begin = %d (== is title bar hovered)\n" 2069 "IsItemActive() after begin = %d (== is window being clicked/moved)\n", 2070 ImGui::IsItemHovered(), ImGui::IsItemActive()); 2071 ImGui::End(); 2072 } 2073 2074 ImGui::TreePop(); 2075 } 2076 } 2077 2078 static void ShowDemoWindowLayout() 2079 { 2080 if (!ImGui::CollapsingHeader("Layout & Scrolling")) 2081 return; 2082 2083 if (ImGui::TreeNode("Child windows")) 2084 { 2085 HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); 2086 static bool disable_mouse_wheel = false; 2087 static bool disable_menu = false; 2088 ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel); 2089 ImGui::Checkbox("Disable Menu", &disable_menu); 2090 2091 // Child 1: no border, enable horizontal scrollbar 2092 { 2093 ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; 2094 if (disable_mouse_wheel) 2095 window_flags |= ImGuiWindowFlags_NoScrollWithMouse; 2096 ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); 1118 2097 for (int i = 0; i < 100; i++) 1119 { 1120 ImGui::Text("%04d: scrollable region", i); 1121 if (goto_line && line == i) 1122 ImGui::SetScrollHere(); 1123 } 1124 if (goto_line && line >= 100) 1125 ImGui::SetScrollHere(); 2098 ImGui::Text("%04d: scrollable region", i); 1126 2099 ImGui::EndChild(); 1127 } 1128 1129 ImGui::SameLine(); 1130 1131 // Child 2: rounded border 1132 { 2100 } 2101 2102 ImGui::SameLine(); 2103 2104 // Child 2: rounded border 2105 { 2106 ImGuiWindowFlags window_flags = ImGuiWindowFlags_None; 2107 if (disable_mouse_wheel) 2108 window_flags |= ImGuiWindowFlags_NoScrollWithMouse; 2109 if (!disable_menu) 2110 window_flags |= ImGuiWindowFlags_MenuBar; 1133 2111 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); 1134 ImGui::BeginChild("Child 2", ImVec2(0, 300), true, (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar));2112 ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); 1135 2113 if (!disable_menu && ImGui::BeginMenuBar()) 1136 2114 { 1137 if (ImGui::BeginMenu("Menu"))1138 {1139 ShowExampleMenuFile();1140 ImGui::EndMenu();1141 }1142 ImGui::EndMenuBar();2115 if (ImGui::BeginMenu("Menu")) 2116 { 2117 ShowExampleMenuFile(); 2118 ImGui::EndMenu(); 2119 } 2120 ImGui::EndMenuBar(); 1143 2121 } 1144 2122 ImGui::Columns(2); 1145 2123 for (int i = 0; i < 100; i++) 1146 2124 { 1147 if (i == 50) 1148 ImGui::NextColumn(); 1149 char buf[32]; 1150 sprintf(buf, "%08x", i * 5731); 1151 ImGui::Button(buf, ImVec2(-1.0f, 0.0f)); 2125 char buf[32]; 2126 sprintf(buf, "%03d", i); 2127 ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); 2128 ImGui::NextColumn(); 1152 2129 } 1153 2130 ImGui::EndChild(); 1154 2131 ImGui::PopStyleVar(); 1155 } 1156 1157 ImGui::TreePop(); 1158 } 1159 1160 if (ImGui::TreeNode("Widgets Width")) 1161 { 1162 static float f = 0.0f; 1163 ImGui::Text("PushItemWidth(100)"); 1164 ImGui::SameLine(); ShowHelpMarker("Fixed width."); 1165 ImGui::PushItemWidth(100); 1166 ImGui::DragFloat("float##1", &f); 1167 ImGui::PopItemWidth(); 1168 1169 ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f)"); 1170 ImGui::SameLine(); ShowHelpMarker("Half of window width."); 1171 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f); 1172 ImGui::DragFloat("float##2", &f); 1173 ImGui::PopItemWidth(); 1174 1175 ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)"); 1176 ImGui::SameLine(); ShowHelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); 1177 ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f); 1178 ImGui::DragFloat("float##3", &f); 1179 ImGui::PopItemWidth(); 1180 1181 ImGui::Text("PushItemWidth(-100)"); 1182 ImGui::SameLine(); ShowHelpMarker("Align to right edge minus 100"); 1183 ImGui::PushItemWidth(-100); 1184 ImGui::DragFloat("float##4", &f); 1185 ImGui::PopItemWidth(); 1186 1187 ImGui::Text("PushItemWidth(-1)"); 1188 ImGui::SameLine(); ShowHelpMarker("Align to right edge"); 1189 ImGui::PushItemWidth(-1); 1190 ImGui::DragFloat("float##5", &f); 1191 ImGui::PopItemWidth(); 1192 1193 ImGui::TreePop(); 1194 } 1195 1196 if (ImGui::TreeNode("Basic Horizontal Layout")) 1197 { 1198 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); 1199 1200 // Text 1201 ImGui::Text("Two items: Hello"); ImGui::SameLine(); 1202 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); 1203 1204 // Adjust spacing 1205 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); 1206 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor"); 1207 1208 // Button 1209 ImGui::AlignTextToFramePadding(); 1210 ImGui::Text("Normal buttons"); ImGui::SameLine(); 1211 ImGui::Button("Banana"); ImGui::SameLine(); 1212 ImGui::Button("Apple"); ImGui::SameLine(); 1213 ImGui::Button("Corniflower"); 1214 1215 // Button 1216 ImGui::Text("Small buttons"); ImGui::SameLine(); 1217 ImGui::SmallButton("Like this one"); ImGui::SameLine(); 1218 ImGui::Text("can fit within a text block."); 1219 1220 // Aligned to arbitrary position. Easy/cheap column. 1221 ImGui::Text("Aligned"); 1222 ImGui::SameLine(150); ImGui::Text("x=150"); 1223 ImGui::SameLine(300); ImGui::Text("x=300"); 1224 ImGui::Text("Aligned"); 1225 ImGui::SameLine(150); ImGui::SmallButton("x=150"); 1226 ImGui::SameLine(300); ImGui::SmallButton("x=300"); 1227 1228 // Checkbox 1229 static bool c1 = false, c2 = false, c3 = false, c4 = false; 1230 ImGui::Checkbox("My", &c1); ImGui::SameLine(); 1231 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); 1232 ImGui::Checkbox("Is", &c3); ImGui::SameLine(); 1233 ImGui::Checkbox("Rich", &c4); 1234 1235 // Various 1236 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; 1237 ImGui::PushItemWidth(80); 1238 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; 1239 static int item = -1; 1240 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); 1241 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); 1242 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); 1243 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); 1244 ImGui::PopItemWidth(); 1245 1246 ImGui::PushItemWidth(80); 1247 ImGui::Text("Lists:"); 1248 static int selection[4] = { 0, 1, 2, 3 }; 1249 for (int i = 0; i < 4; i++) 1250 { 2132 } 2133 2134 ImGui::Separator(); 2135 2136 // Demonstrate a few extra things 2137 // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) 2138 // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window) 2139 // You can also call SetNextWindowPos() to position the child window. The parent window will effectively 2140 // layout from this position. 2141 // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from 2142 // the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details. 2143 { 2144 static int offset_x = 0; 2145 ImGui::SetNextItemWidth(100); 2146 ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); 2147 2148 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); 2149 ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); 2150 ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); 2151 for (int n = 0; n < 50; n++) 2152 ImGui::Text("Some test %d", n); 2153 ImGui::EndChild(); 2154 bool child_is_hovered = ImGui::IsItemHovered(); 2155 ImVec2 child_rect_min = ImGui::GetItemRectMin(); 2156 ImVec2 child_rect_max = ImGui::GetItemRectMax(); 2157 ImGui::PopStyleColor(); 2158 ImGui::Text("Hovered: %d", child_is_hovered); 2159 ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); 2160 } 2161 2162 ImGui::TreePop(); 2163 } 2164 2165 if (ImGui::TreeNode("Widgets Width")) 2166 { 2167 // Use SetNextItemWidth() to set the width of a single upcoming item. 2168 // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. 2169 // In real code use you'll probably want to choose width values that are proportional to your font size 2170 // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc. 2171 2172 static float f = 0.0f; 2173 ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); 2174 ImGui::SameLine(); HelpMarker("Fixed width."); 2175 ImGui::SetNextItemWidth(100); 2176 ImGui::DragFloat("float##1", &f); 2177 2178 ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)"); 2179 ImGui::SameLine(); HelpMarker("Half of window width."); 2180 ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f); 2181 ImGui::DragFloat("float##2", &f); 2182 2183 ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)"); 2184 ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); 2185 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.5f); 2186 ImGui::DragFloat("float##3", &f); 2187 2188 ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); 2189 ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); 2190 ImGui::SetNextItemWidth(-100); 2191 ImGui::DragFloat("float##4", &f); 2192 2193 // Demonstrate using PushItemWidth to surround three items. 2194 // Calling SetNextItemWidth() before each of them would have the same effect. 2195 ImGui::Text("SetNextItemWidth/PushItemWidth(-1)"); 2196 ImGui::SameLine(); HelpMarker("Align to right edge"); 2197 ImGui::PushItemWidth(-1); 2198 ImGui::DragFloat("##float5a", &f); 2199 ImGui::DragFloat("##float5b", &f); 2200 ImGui::DragFloat("##float5c", &f); 2201 ImGui::PopItemWidth(); 2202 2203 ImGui::TreePop(); 2204 } 2205 2206 if (ImGui::TreeNode("Basic Horizontal Layout")) 2207 { 2208 ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)"); 2209 2210 // Text 2211 ImGui::Text("Two items: Hello"); ImGui::SameLine(); 2212 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 2213 2214 // Adjust spacing 2215 ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20); 2216 ImGui::TextColored(ImVec4(1,1,0,1), "Sailor"); 2217 2218 // Button 2219 ImGui::AlignTextToFramePadding(); 2220 ImGui::Text("Normal buttons"); ImGui::SameLine(); 2221 ImGui::Button("Banana"); ImGui::SameLine(); 2222 ImGui::Button("Apple"); ImGui::SameLine(); 2223 ImGui::Button("Corniflower"); 2224 2225 // Button 2226 ImGui::Text("Small buttons"); ImGui::SameLine(); 2227 ImGui::SmallButton("Like this one"); ImGui::SameLine(); 2228 ImGui::Text("can fit within a text block."); 2229 2230 // Aligned to arbitrary position. Easy/cheap column. 2231 ImGui::Text("Aligned"); 2232 ImGui::SameLine(150); ImGui::Text("x=150"); 2233 ImGui::SameLine(300); ImGui::Text("x=300"); 2234 ImGui::Text("Aligned"); 2235 ImGui::SameLine(150); ImGui::SmallButton("x=150"); 2236 ImGui::SameLine(300); ImGui::SmallButton("x=300"); 2237 2238 // Checkbox 2239 static bool c1 = false, c2 = false, c3 = false, c4 = false; 2240 ImGui::Checkbox("My", &c1); ImGui::SameLine(); 2241 ImGui::Checkbox("Tailor", &c2); ImGui::SameLine(); 2242 ImGui::Checkbox("Is", &c3); ImGui::SameLine(); 2243 ImGui::Checkbox("Rich", &c4); 2244 2245 // Various 2246 static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f; 2247 ImGui::PushItemWidth(80); 2248 const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" }; 2249 static int item = -1; 2250 ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); 2251 ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine(); 2252 ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine(); 2253 ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f); 2254 ImGui::PopItemWidth(); 2255 2256 ImGui::PushItemWidth(80); 2257 ImGui::Text("Lists:"); 2258 static int selection[4] = { 0, 1, 2, 3 }; 2259 for (int i = 0; i < 4; i++) 2260 { 1251 2261 if (i > 0) ImGui::SameLine(); 1252 2262 ImGui::PushID(i); … … 1254 2264 ImGui::PopID(); 1255 2265 //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i); 1256 } 1257 ImGui::PopItemWidth(); 1258 1259 // Dummy 1260 ImVec2 sz(30, 30); 1261 ImGui::Button("A", sz); ImGui::SameLine(); 1262 ImGui::Dummy(sz); ImGui::SameLine(); 1263 ImGui::Button("B", sz); 1264 1265 ImGui::TreePop(); 1266 } 1267 1268 if (ImGui::TreeNode("Groups")) 1269 { 1270 ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)"); 1271 ImGui::BeginGroup(); 1272 { 2266 } 2267 ImGui::PopItemWidth(); 2268 2269 // Dummy 2270 ImVec2 button_sz(40, 40); 2271 ImGui::Button("A", button_sz); ImGui::SameLine(); 2272 ImGui::Dummy(button_sz); ImGui::SameLine(); 2273 ImGui::Button("B", button_sz); 2274 2275 // Manually wrapping 2276 // (we should eventually provide this as an automatic layout feature, but for now you can do it manually) 2277 ImGui::Text("Manually wrapping:"); 2278 ImGuiStyle& style = ImGui::GetStyle(); 2279 int buttons_count = 20; 2280 float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; 2281 for (int n = 0; n < buttons_count; n++) 2282 { 2283 ImGui::PushID(n); 2284 ImGui::Button("Box", button_sz); 2285 float last_button_x2 = ImGui::GetItemRectMax().x; 2286 float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line 2287 if (n + 1 < buttons_count && next_button_x2 < window_visible_x2) 2288 ImGui::SameLine(); 2289 ImGui::PopID(); 2290 } 2291 2292 ImGui::TreePop(); 2293 } 2294 2295 if (ImGui::TreeNode("Tabs")) 2296 { 2297 if (ImGui::TreeNode("Basic")) 2298 { 2299 ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; 2300 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 2301 { 2302 if (ImGui::BeginTabItem("Avocado")) 2303 { 2304 ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); 2305 ImGui::EndTabItem(); 2306 } 2307 if (ImGui::BeginTabItem("Broccoli")) 2308 { 2309 ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); 2310 ImGui::EndTabItem(); 2311 } 2312 if (ImGui::BeginTabItem("Cucumber")) 2313 { 2314 ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); 2315 ImGui::EndTabItem(); 2316 } 2317 ImGui::EndTabBar(); 2318 } 2319 ImGui::Separator(); 2320 ImGui::TreePop(); 2321 } 2322 2323 if (ImGui::TreeNode("Advanced & Close Button")) 2324 { 2325 // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). 2326 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; 2327 ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); 2328 ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); 2329 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); 2330 ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); 2331 if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) 2332 tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; 2333 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) 2334 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); 2335 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) 2336 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); 2337 2338 // Tab Bar 2339 const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; 2340 static bool opened[4] = { true, true, true, true }; // Persistent user state 2341 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 2342 { 2343 if (n > 0) { ImGui::SameLine(); } 2344 ImGui::Checkbox(names[n], &opened[n]); 2345 } 2346 2347 // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): 2348 // the underlying bool will be set to false when the tab is closed. 2349 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 2350 { 2351 for (int n = 0; n < IM_ARRAYSIZE(opened); n++) 2352 if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) 2353 { 2354 ImGui::Text("This is the %s tab!", names[n]); 2355 if (n & 1) 2356 ImGui::Text("I am an odd tab."); 2357 ImGui::EndTabItem(); 2358 } 2359 ImGui::EndTabBar(); 2360 } 2361 ImGui::Separator(); 2362 ImGui::TreePop(); 2363 } 2364 2365 if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) 2366 { 2367 static ImVector<int> active_tabs; 2368 static int next_tab_id = 0; 2369 if (next_tab_id == 0) // Initialize with some default tabs 2370 for (int i = 0; i < 3; i++) 2371 active_tabs.push_back(next_tab_id++); 2372 2373 // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. 2374 // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... 2375 // but they tend to make more sense together) 2376 static bool show_leading_button = true; 2377 static bool show_trailing_button = true; 2378 ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); 2379 ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); 2380 2381 // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs 2382 static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; 2383 ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); 2384 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) 2385 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); 2386 if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) 2387 tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); 2388 2389 if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) 2390 { 2391 // Demo a Leading TabItemButton(): click the "?" button to open a menu 2392 if (show_leading_button) 2393 if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) 2394 ImGui::OpenPopup("MyHelpMenu"); 2395 if (ImGui::BeginPopup("MyHelpMenu")) 2396 { 2397 ImGui::Selectable("Hello!"); 2398 ImGui::EndPopup(); 2399 } 2400 2401 // Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+") 2402 // Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end. 2403 if (show_trailing_button) 2404 if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) 2405 active_tabs.push_back(next_tab_id++); // Add new tab 2406 2407 // Submit our regular tabs 2408 for (int n = 0; n < active_tabs.Size; ) 2409 { 2410 bool open = true; 2411 char name[16]; 2412 snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); 2413 if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) 2414 { 2415 ImGui::Text("This is the %s tab!", name); 2416 ImGui::EndTabItem(); 2417 } 2418 2419 if (!open) 2420 active_tabs.erase(active_tabs.Data + n); 2421 else 2422 n++; 2423 } 2424 2425 ImGui::EndTabBar(); 2426 } 2427 ImGui::Separator(); 2428 ImGui::TreePop(); 2429 } 2430 ImGui::TreePop(); 2431 } 2432 2433 if (ImGui::TreeNode("Groups")) 2434 { 2435 HelpMarker( 2436 "BeginGroup() basically locks the horizontal position for new line. " 2437 "EndGroup() bundles the whole group so that you can use \"item\" functions such as " 2438 "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group."); 2439 ImGui::BeginGroup(); 2440 { 1273 2441 ImGui::BeginGroup(); 1274 2442 ImGui::Button("AAA"); … … 1284 2452 ImGui::EndGroup(); 1285 2453 if (ImGui::IsItemHovered()) 1286 ImGui::SetTooltip("First group hovered");1287 1288 1289 1290 1291 1292 1293 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));1294 1295 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));1296 1297 1298 1299 1300 1301 1302 1303 2454 ImGui::SetTooltip("First group hovered"); 2455 } 2456 // Capture the group size and create widgets using the same size 2457 ImVec2 size = ImGui::GetItemRectSize(); 2458 const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f }; 2459 ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size); 2460 2461 ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); 2462 ImGui::SameLine(); 2463 ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y)); 2464 ImGui::EndGroup(); 2465 ImGui::SameLine(); 2466 2467 ImGui::Button("LEVERAGE\nBUZZWORD", size); 2468 ImGui::SameLine(); 2469 2470 if (ImGui::ListBoxHeader("List", size)) 2471 { 1304 2472 ImGui::Selectable("Selected", true); 1305 2473 ImGui::Selectable("Not Selected", false); 1306 2474 ImGui::ListBoxFooter(); 1307 } 1308 1309 ImGui::TreePop(); 1310 } 1311 1312 if (ImGui::TreeNode("Text Baseline Alignment")) 1313 { 1314 ImGui::TextWrapped("(This is testing the vertical alignment that occurs on text to keep it at the same baseline as widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets)"); 1315 1316 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); 1317 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1318 ImGui::Text("Banana"); 1319 1320 ImGui::Text("Banana"); ImGui::SameLine(); 1321 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1322 ImGui::Text("One\nTwo\nThree"); 1323 1324 ImGui::Button("HOP##1"); ImGui::SameLine(); 1325 ImGui::Text("Banana"); ImGui::SameLine(); 1326 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1327 ImGui::Text("Banana"); 1328 1329 ImGui::Button("HOP##2"); ImGui::SameLine(); 1330 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 1331 ImGui::Text("Banana"); 1332 1333 ImGui::Button("TEST##1"); ImGui::SameLine(); 1334 ImGui::Text("TEST"); ImGui::SameLine(); 1335 ImGui::SmallButton("TEST##2"); 1336 1337 ImGui::AlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets. 1338 ImGui::Text("Text aligned to Widget"); ImGui::SameLine(); 1339 ImGui::Button("Widget##1"); ImGui::SameLine(); 1340 ImGui::Text("Widget"); ImGui::SameLine(); 1341 ImGui::SmallButton("Widget##2"); ImGui::SameLine(); 1342 ImGui::Button("Widget##3"); 1343 1344 // Tree 1345 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 1346 ImGui::Button("Button##1"); 1347 ImGui::SameLine(0.0f, spacing); 1348 if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data 1349 1350 ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit). 1351 bool node_open = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content. 1352 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); 1353 if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data 1354 1355 // Bullet 1356 ImGui::Button("Button##3"); 1357 ImGui::SameLine(0.0f, spacing); 1358 ImGui::BulletText("Bullet text"); 1359 1360 ImGui::AlignTextToFramePadding(); 1361 ImGui::BulletText("Node"); 1362 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); 1363 1364 ImGui::TreePop(); 1365 } 1366 1367 if (ImGui::TreeNode("Scrolling")) 1368 { 1369 ImGui::TextWrapped("(Use SetScrollHere() or SetScrollFromPosY() to scroll to a given position.)"); 1370 static bool track = true; 1371 static int track_line = 50, scroll_to_px = 200; 1372 ImGui::Checkbox("Track", &track); 1373 ImGui::PushItemWidth(100); 1374 ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %.0f"); 1375 bool scroll_to = ImGui::Button("Scroll To Pos"); 1376 ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %.0f px"); 1377 ImGui::PopItemWidth(); 1378 if (scroll_to) track = false; 1379 1380 for (int i = 0; i < 5; i++) 1381 { 2475 } 2476 2477 ImGui::TreePop(); 2478 } 2479 2480 if (ImGui::TreeNode("Text Baseline Alignment")) 2481 { 2482 { 2483 ImGui::BulletText("Text baseline:"); 2484 ImGui::SameLine(); HelpMarker( 2485 "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. " 2486 "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets."); 2487 ImGui::Indent(); 2488 2489 ImGui::Text("KO Blahblah"); ImGui::SameLine(); 2490 ImGui::Button("Some framed item"); ImGui::SameLine(); 2491 HelpMarker("Baseline of button will look misaligned with text.."); 2492 2493 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2494 // (because we don't know what's coming after the Text() statement, we need to move the text baseline 2495 // down by FramePadding.y ahead of time) 2496 ImGui::AlignTextToFramePadding(); 2497 ImGui::Text("OK Blahblah"); ImGui::SameLine(); 2498 ImGui::Button("Some framed item"); ImGui::SameLine(); 2499 HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); 2500 2501 // SmallButton() uses the same vertical padding as Text 2502 ImGui::Button("TEST##1"); ImGui::SameLine(); 2503 ImGui::Text("TEST"); ImGui::SameLine(); 2504 ImGui::SmallButton("TEST##2"); 2505 2506 // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets. 2507 ImGui::AlignTextToFramePadding(); 2508 ImGui::Text("Text aligned to framed item"); ImGui::SameLine(); 2509 ImGui::Button("Item##1"); ImGui::SameLine(); 2510 ImGui::Text("Item"); ImGui::SameLine(); 2511 ImGui::SmallButton("Item##2"); ImGui::SameLine(); 2512 ImGui::Button("Item##3"); 2513 2514 ImGui::Unindent(); 2515 } 2516 2517 ImGui::Spacing(); 2518 2519 { 2520 ImGui::BulletText("Multi-line text:"); 2521 ImGui::Indent(); 2522 ImGui::Text("One\nTwo\nThree"); ImGui::SameLine(); 2523 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2524 ImGui::Text("Banana"); 2525 2526 ImGui::Text("Banana"); ImGui::SameLine(); 2527 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2528 ImGui::Text("One\nTwo\nThree"); 2529 2530 ImGui::Button("HOP##1"); ImGui::SameLine(); 2531 ImGui::Text("Banana"); ImGui::SameLine(); 2532 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2533 ImGui::Text("Banana"); 2534 2535 ImGui::Button("HOP##2"); ImGui::SameLine(); 2536 ImGui::Text("Hello\nWorld"); ImGui::SameLine(); 2537 ImGui::Text("Banana"); 2538 ImGui::Unindent(); 2539 } 2540 2541 ImGui::Spacing(); 2542 2543 { 2544 ImGui::BulletText("Misc items:"); 2545 ImGui::Indent(); 2546 2547 // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button. 2548 ImGui::Button("80x80", ImVec2(80, 80)); 2549 ImGui::SameLine(); 2550 ImGui::Button("50x50", ImVec2(50, 50)); 2551 ImGui::SameLine(); 2552 ImGui::Button("Button()"); 2553 ImGui::SameLine(); 2554 ImGui::SmallButton("SmallButton()"); 2555 2556 // Tree 2557 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; 2558 ImGui::Button("Button##1"); 2559 ImGui::SameLine(0.0f, spacing); 2560 if (ImGui::TreeNode("Node##1")) 2561 { 2562 // Placeholder tree data 2563 for (int i = 0; i < 6; i++) 2564 ImGui::BulletText("Item %d..", i); 2565 ImGui::TreePop(); 2566 } 2567 2568 // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. 2569 // Otherwise you can use SmallButton() (smaller fit). 2570 ImGui::AlignTextToFramePadding(); 2571 2572 // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add 2573 // other contents below the node. 2574 bool node_open = ImGui::TreeNode("Node##2"); 2575 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); 2576 if (node_open) 2577 { 2578 // Placeholder tree data 2579 for (int i = 0; i < 6; i++) 2580 ImGui::BulletText("Item %d..", i); 2581 ImGui::TreePop(); 2582 } 2583 2584 // Bullet 2585 ImGui::Button("Button##3"); 2586 ImGui::SameLine(0.0f, spacing); 2587 ImGui::BulletText("Bullet text"); 2588 2589 ImGui::AlignTextToFramePadding(); 2590 ImGui::BulletText("Node"); 2591 ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); 2592 ImGui::Unindent(); 2593 } 2594 2595 ImGui::TreePop(); 2596 } 2597 2598 if (ImGui::TreeNode("Scrolling")) 2599 { 2600 // Vertical scroll functions 2601 HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position."); 2602 2603 static int track_item = 50; 2604 static bool enable_track = true; 2605 static bool enable_extra_decorations = false; 2606 static float scroll_to_off_px = 0.0f; 2607 static float scroll_to_pos_px = 200.0f; 2608 2609 ImGui::Checkbox("Decoration", &enable_extra_decorations); 2610 2611 ImGui::Checkbox("Track", &enable_track); 2612 ImGui::PushItemWidth(100); 2613 ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d"); 2614 2615 bool scroll_to_off = ImGui::Button("Scroll Offset"); 2616 ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); 2617 2618 bool scroll_to_pos = ImGui::Button("Scroll To Pos"); 2619 ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); 2620 ImGui::PopItemWidth(); 2621 2622 if (scroll_to_off || scroll_to_pos) 2623 enable_track = false; 2624 2625 ImGuiStyle& style = ImGui::GetStyle(); 2626 float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5; 2627 if (child_w < 1.0f) 2628 child_w = 1.0f; 2629 ImGui::PushID("##VerticalScrolling"); 2630 for (int i = 0; i < 5; i++) 2631 { 1382 2632 if (i > 0) ImGui::SameLine(); 1383 2633 ImGui::BeginGroup(); 1384 ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom"); 1385 ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true); 1386 if (scroll_to) 1387 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f); 1388 for (int line = 0; line < 100; line++) 1389 { 1390 if (track && line == track_line) 1391 { 1392 ImGui::TextColored(ImColor(255, 255, 0), "Line %d", line); 1393 ImGui::SetScrollHere(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom 1394 } 1395 else 1396 { 1397 ImGui::Text("Line %d", line); 1398 } 1399 } 1400 float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY(); 2634 const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" }; 2635 ImGui::TextUnformatted(names[i]); 2636 2637 const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; 2638 const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); 2639 const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); 2640 if (ImGui::BeginMenuBar()) 2641 { 2642 ImGui::TextUnformatted("abc"); 2643 ImGui::EndMenuBar(); 2644 } 2645 if (scroll_to_off) 2646 ImGui::SetScrollY(scroll_to_off_px); 2647 if (scroll_to_pos) 2648 ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); 2649 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items 2650 { 2651 for (int item = 0; item < 100; item++) 2652 { 2653 if (enable_track && item == track_item) 2654 { 2655 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2656 ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom 2657 } 2658 else 2659 { 2660 ImGui::Text("Item %d", item); 2661 } 2662 } 2663 } 2664 float scroll_y = ImGui::GetScrollY(); 2665 float scroll_max_y = ImGui::GetScrollMaxY(); 1401 2666 ImGui::EndChild(); 1402 ImGui::Text("%.0f/% 0.f", scroll_y, scroll_max_y);2667 ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); 1403 2668 ImGui::EndGroup(); 1404 } 1405 ImGui::TreePop(); 1406 } 1407 1408 if (ImGui::TreeNode("Horizontal Scrolling")) 1409 { 1410 ImGui::Bullet(); ImGui::TextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag."); 1411 ImGui::Bullet(); ImGui::TextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); 1412 static int lines = 7; 1413 ImGui::SliderInt("Lines", &lines, 1, 15); 1414 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 1415 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); 1416 ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar); 1417 for (int line = 0; line < lines; line++) 1418 { 1419 // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off 1420 // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API) 2669 } 2670 ImGui::PopID(); 2671 2672 // Horizontal scroll functions 2673 ImGui::Spacing(); 2674 HelpMarker( 2675 "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n" 2676 "Because the clipping rectangle of most window hides half worth of WindowPadding on the " 2677 "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the " 2678 "equivalent SetScrollFromPosY(+1) wouldn't."); 2679 ImGui::PushID("##HorizontalScrolling"); 2680 for (int i = 0; i < 5; i++) 2681 { 2682 float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; 2683 ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); 2684 ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); 2685 bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); 2686 if (scroll_to_off) 2687 ImGui::SetScrollX(scroll_to_off_px); 2688 if (scroll_to_pos) 2689 ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); 2690 if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items 2691 { 2692 for (int item = 0; item < 100; item++) 2693 { 2694 if (enable_track && item == track_item) 2695 { 2696 ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item); 2697 ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right 2698 } 2699 else 2700 { 2701 ImGui::Text("Item %d", item); 2702 } 2703 ImGui::SameLine(); 2704 } 2705 } 2706 float scroll_x = ImGui::GetScrollX(); 2707 float scroll_max_x = ImGui::GetScrollMaxX(); 2708 ImGui::EndChild(); 2709 ImGui::SameLine(); 2710 const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; 2711 ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); 2712 ImGui::Spacing(); 2713 } 2714 ImGui::PopID(); 2715 2716 // Miscellaneous Horizontal Scrolling Demo 2717 HelpMarker( 2718 "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n" 2719 "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin()."); 2720 static int lines = 7; 2721 ImGui::SliderInt("Lines", &lines, 1, 15); 2722 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 2723 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); 2724 ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); 2725 ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); 2726 for (int line = 0; line < lines; line++) 2727 { 2728 // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() 2729 // If you want to create your own time line for a real application you may be better off manipulating 2730 // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets 2731 // yourself. You may also want to use the lower-level ImDrawList API. 1421 2732 int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); 1422 2733 for (int n = 0; n < num_buttons; n++) 1423 2734 { 1424 if (n > 0) ImGui::SameLine(); 1425 ImGui::PushID(n + line * 1000); 1426 char num_buf[16]; 1427 sprintf(num_buf, "%d", n); 1428 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; 1429 float hue = n * 0.05f; 1430 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); 1431 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); 1432 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); 1433 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); 1434 ImGui::PopStyleColor(3); 1435 ImGui::PopID(); 1436 } 1437 } 1438 float scroll_x = ImGui::GetScrollX(), scroll_max_x = ImGui::GetScrollMaxX(); 1439 ImGui::EndChild(); 1440 ImGui::PopStyleVar(2); 1441 float scroll_x_delta = 0.0f; 1442 ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); 1443 ImGui::Text("Scroll from code"); ImGui::SameLine(); 1444 ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine(); 1445 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); 1446 if (scroll_x_delta != 0.0f) 1447 { 1448 ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window) 2735 if (n > 0) ImGui::SameLine(); 2736 ImGui::PushID(n + line * 1000); 2737 char num_buf[16]; 2738 sprintf(num_buf, "%d", n); 2739 const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; 2740 float hue = n * 0.05f; 2741 ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); 2742 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); 2743 ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); 2744 ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); 2745 ImGui::PopStyleColor(3); 2746 ImGui::PopID(); 2747 } 2748 } 2749 float scroll_x = ImGui::GetScrollX(); 2750 float scroll_max_x = ImGui::GetScrollMaxX(); 2751 ImGui::EndChild(); 2752 ImGui::PopStyleVar(2); 2753 float scroll_x_delta = 0.0f; 2754 ImGui::SmallButton("<<"); 2755 if (ImGui::IsItemActive()) 2756 scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; 2757 ImGui::SameLine(); 2758 ImGui::Text("Scroll from code"); ImGui::SameLine(); 2759 ImGui::SmallButton(">>"); 2760 if (ImGui::IsItemActive()) 2761 scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; 2762 ImGui::SameLine(); 2763 ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x); 2764 if (scroll_x_delta != 0.0f) 2765 { 2766 // Demonstrate a trick: you can use Begin to set yourself in the context of another window 2767 // (here we are already out of your child window) 2768 ImGui::BeginChild("scrolling"); 1449 2769 ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); 2770 ImGui::EndChild(); 2771 } 2772 ImGui::Spacing(); 2773 2774 static bool show_horizontal_contents_size_demo_window = false; 2775 ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); 2776 2777 if (show_horizontal_contents_size_demo_window) 2778 { 2779 static bool show_h_scrollbar = true; 2780 static bool show_button = true; 2781 static bool show_tree_nodes = true; 2782 static bool show_text_wrapped = false; 2783 static bool show_columns = true; 2784 static bool show_tab_bar = true; 2785 static bool show_child = false; 2786 static bool explicit_content_size = false; 2787 static float contents_size_x = 300.0f; 2788 if (explicit_content_size) 2789 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); 2790 ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); 2791 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); 2792 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); 2793 HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); 2794 ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); 2795 ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) 2796 ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width 2797 ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size 2798 ImGui::Checkbox("Columns", &show_columns); // Will use contents size 2799 ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size 2800 ImGui::Checkbox("Child", &show_child); // Will grow and use contents size 2801 ImGui::Checkbox("Explicit content size", &explicit_content_size); 2802 ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); 2803 if (explicit_content_size) 2804 { 2805 ImGui::SameLine(); 2806 ImGui::SetNextItemWidth(100); 2807 ImGui::DragFloat("##csx", &contents_size_x); 2808 ImVec2 p = ImGui::GetCursorScreenPos(); 2809 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); 2810 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); 2811 ImGui::Dummy(ImVec2(0, 10)); 2812 } 2813 ImGui::PopStyleVar(2); 2814 ImGui::Separator(); 2815 if (show_button) 2816 { 2817 ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); 2818 } 2819 if (show_tree_nodes) 2820 { 2821 bool open = true; 2822 if (ImGui::TreeNode("this is a tree node")) 2823 { 2824 if (ImGui::TreeNode("another one of those tree node...")) 2825 { 2826 ImGui::Text("Some tree contents"); 2827 ImGui::TreePop(); 2828 } 2829 ImGui::TreePop(); 2830 } 2831 ImGui::CollapsingHeader("CollapsingHeader", &open); 2832 } 2833 if (show_text_wrapped) 2834 { 2835 ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); 2836 } 2837 if (show_columns) 2838 { 2839 ImGui::Columns(4); 2840 for (int n = 0; n < 4; n++) 2841 { 2842 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 2843 ImGui::NextColumn(); 2844 } 2845 ImGui::Columns(1); 2846 } 2847 if (show_tab_bar && ImGui::BeginTabBar("Hello")) 2848 { 2849 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } 2850 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } 2851 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } 2852 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } 2853 ImGui::EndTabBar(); 2854 } 2855 if (show_child) 2856 { 2857 ImGui::BeginChild("child", ImVec2(0, 0), true); 2858 ImGui::EndChild(); 2859 } 1450 2860 ImGui::End(); 1451 } 1452 ImGui::TreePop(); 1453 } 1454 1455 if (ImGui::TreeNode("Clipping")) 1456 { 1457 static ImVec2 size(100, 100), offset(50, 20); 1458 ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost."); 1459 ImGui::DragFloat2("size", (float*)&size, 0.5f, 0.0f, 200.0f, "%.0f"); 1460 ImGui::TextWrapped("(Click and drag)"); 1461 ImVec2 pos = ImGui::GetCursorScreenPos(); 1462 ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); 1463 ImGui::InvisibleButton("##dummy", size); 1464 if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; } 1465 ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255)); 1466 ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32(255, 255, 255, 255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect); 1467 ImGui::TreePop(); 1468 } 1469 } 1470 1471 if (ImGui::CollapsingHeader("Popups & Modal windows")) 1472 { 1473 if (ImGui::TreeNode("Popups")) 1474 { 1475 ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it."); 1476 1477 static int selected_fish = -1; 1478 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; 1479 static bool toggles[] = { true, false, false, false, false }; 1480 1481 // Simple selection popup 1482 // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label) 1483 if (ImGui::Button("Select..")) 1484 ImGui::OpenPopup("select"); 1485 ImGui::SameLine(); 1486 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]); 1487 if (ImGui::BeginPopup("select")) 1488 { 2861 } 2862 2863 ImGui::TreePop(); 2864 } 2865 2866 if (ImGui::TreeNode("Clipping")) 2867 { 2868 static ImVec2 size(100.0f, 100.0f); 2869 static ImVec2 offset(30.0f, 30.0f); 2870 ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f"); 2871 ImGui::TextWrapped("(Click and drag to scroll)"); 2872 2873 for (int n = 0; n < 3; n++) 2874 { 2875 if (n > 0) 2876 ImGui::SameLine(); 2877 ImGui::PushID(n); 2878 ImGui::BeginGroup(); // Lock X position 2879 2880 ImGui::InvisibleButton("##empty", size); 2881 if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) 2882 { 2883 offset.x += ImGui::GetIO().MouseDelta.x; 2884 offset.y += ImGui::GetIO().MouseDelta.y; 2885 } 2886 const ImVec2 p0 = ImGui::GetItemRectMin(); 2887 const ImVec2 p1 = ImGui::GetItemRectMax(); 2888 const char* text_str = "Line 1 hello\nLine 2 clip me!"; 2889 const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y); 2890 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2891 2892 switch (n) 2893 { 2894 case 0: 2895 HelpMarker( 2896 "Using ImGui::PushClipRect():\n" 2897 "Will alter ImGui hit-testing logic + ImDrawList rendering.\n" 2898 "(use this if you want your clipping rectangle to affect interactions)"); 2899 ImGui::PushClipRect(p0, p1, true); 2900 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 2901 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); 2902 ImGui::PopClipRect(); 2903 break; 2904 case 1: 2905 HelpMarker( 2906 "Using ImDrawList::PushClipRect():\n" 2907 "Will alter ImDrawList rendering only.\n" 2908 "(use this as a shortcut if you are only using ImDrawList calls)"); 2909 draw_list->PushClipRect(p0, p1, true); 2910 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 2911 draw_list->AddText(text_pos, IM_COL32_WHITE, text_str); 2912 draw_list->PopClipRect(); 2913 break; 2914 case 2: 2915 HelpMarker( 2916 "Using ImDrawList::AddText() with a fine ClipRect:\n" 2917 "Will alter only this specific ImDrawList::AddText() rendering.\n" 2918 "(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)"); 2919 ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert. 2920 draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255)); 2921 draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect); 2922 break; 2923 } 2924 ImGui::EndGroup(); 2925 ImGui::PopID(); 2926 } 2927 2928 ImGui::TreePop(); 2929 } 2930 } 2931 2932 static void ShowDemoWindowPopups() 2933 { 2934 if (!ImGui::CollapsingHeader("Popups & Modal windows")) 2935 return; 2936 2937 // The properties of popups windows are: 2938 // - They block normal mouse hovering detection outside them. (*) 2939 // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE. 2940 // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as 2941 // we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup(). 2942 // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even 2943 // when normally blocked by a popup. 2944 // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close 2945 // popups at any time. 2946 2947 // Typical use for regular windows: 2948 // bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End(); 2949 // Typical use for popups: 2950 // if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); } 2951 2952 // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state. 2953 // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below. 2954 2955 if (ImGui::TreeNode("Popups")) 2956 { 2957 ImGui::TextWrapped( 2958 "When a popup is active, it inhibits interacting with windows that are behind the popup. " 2959 "Clicking outside the popup closes it."); 2960 2961 static int selected_fish = -1; 2962 const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; 2963 static bool toggles[] = { true, false, false, false, false }; 2964 2965 // Simple selection popup (if you want to show the current selection inside the Button itself, 2966 // you may want to build a string using the "###" operator to preserve a constant ID with a variable label) 2967 if (ImGui::Button("Select..")) 2968 ImGui::OpenPopup("my_select_popup"); 2969 ImGui::SameLine(); 2970 ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]); 2971 if (ImGui::BeginPopup("my_select_popup")) 2972 { 1489 2973 ImGui::Text("Aquarium"); 1490 2974 ImGui::Separator(); 1491 2975 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 1492 if (ImGui::Selectable(names[i]))1493 selected_fish = i;2976 if (ImGui::Selectable(names[i])) 2977 selected_fish = i; 1494 2978 ImGui::EndPopup(); 1495 1496 1497 1498 1499 ImGui::OpenPopup(" toggle");1500 if (ImGui::BeginPopup("toggle"))1501 2979 } 2980 2981 // Showing a menu with toggles 2982 if (ImGui::Button("Toggle..")) 2983 ImGui::OpenPopup("my_toggle_popup"); 2984 if (ImGui::BeginPopup("my_toggle_popup")) 2985 { 1502 2986 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 1503 ImGui::MenuItem(names[i], "", &toggles[i]);2987 ImGui::MenuItem(names[i], "", &toggles[i]); 1504 2988 if (ImGui::BeginMenu("Sub-menu")) 1505 2989 { 1506 ImGui::MenuItem("Click me");1507 ImGui::EndMenu();2990 ImGui::MenuItem("Click me"); 2991 ImGui::EndMenu(); 1508 2992 } 1509 2993 … … 1511 2995 ImGui::Text("Tooltip here"); 1512 2996 if (ImGui::IsItemHovered()) 1513 ImGui::SetTooltip("I am a tooltip over a popup");2997 ImGui::SetTooltip("I am a tooltip over a popup"); 1514 2998 1515 2999 if (ImGui::Button("Stacked Popup")) 1516 ImGui::OpenPopup("another popup");3000 ImGui::OpenPopup("another popup"); 1517 3001 if (ImGui::BeginPopup("another popup")) 1518 3002 { 1519 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 1520 ImGui::MenuItem(names[i], "", &toggles[i]); 1521 if (ImGui::BeginMenu("Sub-menu")) 1522 { 1523 ImGui::MenuItem("Click me"); 1524 ImGui::EndMenu(); 1525 } 1526 ImGui::EndPopup(); 3003 for (int i = 0; i < IM_ARRAYSIZE(names); i++) 3004 ImGui::MenuItem(names[i], "", &toggles[i]); 3005 if (ImGui::BeginMenu("Sub-menu")) 3006 { 3007 ImGui::MenuItem("Click me"); 3008 if (ImGui::Button("Stacked Popup")) 3009 ImGui::OpenPopup("another popup"); 3010 if (ImGui::BeginPopup("another popup")) 3011 { 3012 ImGui::Text("I am the last one here."); 3013 ImGui::EndPopup(); 3014 } 3015 ImGui::EndMenu(); 3016 } 3017 ImGui::EndPopup(); 1527 3018 } 1528 3019 ImGui::EndPopup(); 1529 } 1530 1531 if (ImGui::Button("Popup Menu..")) 1532 ImGui::OpenPopup("FilePopup"); 1533 if (ImGui::BeginPopup("FilePopup")) 1534 { 3020 } 3021 3022 // Call the more complete ShowExampleMenuFile which we use in various places of this demo 3023 if (ImGui::Button("File Menu..")) 3024 ImGui::OpenPopup("my_file_popup"); 3025 if (ImGui::BeginPopup("my_file_popup")) 3026 { 1535 3027 ShowExampleMenuFile(); 1536 3028 ImGui::EndPopup(); 1537 } 1538 1539 ImGui::TreePop(); 1540 } 1541 1542 if (ImGui::TreeNode("Context menus")) 1543 { 1544 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: 1545 // if (IsItemHovered() && IsMouseClicked(0)) 1546 // OpenPopup(id); 1547 // return BeginPopup(id); 1548 // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation. 1549 static float value = 0.5f; 1550 ImGui::Text("Value = %.3f (<-- right-click here)", value); 1551 if (ImGui::BeginPopupContextItem("item context menu")) 1552 { 3029 } 3030 3031 ImGui::TreePop(); 3032 } 3033 3034 if (ImGui::TreeNode("Context menus")) 3035 { 3036 // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing: 3037 // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) 3038 // OpenPopup(id); 3039 // return BeginPopup(id); 3040 // For more advanced uses you may want to replicate and customize this code. 3041 // See details in BeginPopupContextItem(). 3042 static float value = 0.5f; 3043 ImGui::Text("Value = %.3f (<-- right-click here)", value); 3044 if (ImGui::BeginPopupContextItem("item context menu")) 3045 { 1553 3046 if (ImGui::Selectable("Set to zero")) value = 0.0f; 1554 3047 if (ImGui::Selectable("Set to PI")) value = 3.1415f; 1555 ImGui:: PushItemWidth(-1);3048 ImGui::SetNextItemWidth(-1); 1556 3049 ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); 1557 ImGui::PopItemWidth();1558 3050 ImGui::EndPopup(); 1559 } 1560 1561 static char name[32] = "Label1"; 1562 char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label 1563 ImGui::Button(buf); 1564 if (ImGui::BeginPopupContextItem()) // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem(). 1565 { 3051 } 3052 3053 // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the 3054 // Begin() call. So here we will make it that clicking on the text field with the right mouse button (1) 3055 // will toggle the visibility of the popup above. 3056 ImGui::Text("(You can also right-click me to open the same popup as above.)"); 3057 ImGui::OpenPopupOnItemClick("item context menu", 1); 3058 3059 // When used after an item that has an ID (e.g.Button), we can skip providing an ID to BeginPopupContextItem(). 3060 // BeginPopupContextItem() will use the last item ID as the popup ID. 3061 // In addition here, we want to include your editable label inside the button label. 3062 // We use the ### operator to override the ID (read FAQ about ID for details) 3063 static char name[32] = "Label1"; 3064 char buf[64]; 3065 sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label 3066 ImGui::Button(buf); 3067 if (ImGui::BeginPopupContextItem()) 3068 { 1566 3069 ImGui::Text("Edit name:"); 1567 3070 ImGui::InputText("##edit", name, IM_ARRAYSIZE(name)); 1568 3071 if (ImGui::Button("Close")) 1569 ImGui::CloseCurrentPopup();3072 ImGui::CloseCurrentPopup(); 1570 3073 ImGui::EndPopup(); 1571 1572 1573 1574 1575 1576 1577 1578 1579 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window.");1580 1581 3074 } 3075 ImGui::SameLine(); ImGui::Text("(<-- right-click here)"); 3076 3077 ImGui::TreePop(); 3078 } 3079 3080 if (ImGui::TreeNode("Modals")) 3081 { 3082 ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside."); 3083 3084 if (ImGui::Button("Delete..")) 1582 3085 ImGui::OpenPopup("Delete?"); 1583 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 1584 { 3086 3087 // Always center this window when appearing 3088 ImVec2 center(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f); 3089 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 3090 3091 if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 3092 { 1585 3093 ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); 1586 3094 ImGui::Separator(); 1587 3095 1588 //static int dummy_i = 0;1589 //ImGui::Combo("Combo", & dummy_i, "Delete\0Delete harder\0");3096 //static int unused_i = 0; 3097 //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0"); 1590 3098 1591 3099 static bool dont_ask_me_next_time = false; … … 1599 3107 if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); } 1600 3108 ImGui::EndPopup(); 1601 1602 1603 3109 } 3110 3111 if (ImGui::Button("Stacked modals..")) 1604 3112 ImGui::OpenPopup("Stacked 1"); 1605 if (ImGui::BeginPopupModal("Stacked 1")) 1606 { 1607 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDarkening] for darkening."); 3113 if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar)) 3114 { 3115 if (ImGui::BeginMenuBar()) 3116 { 3117 if (ImGui::BeginMenu("File")) 3118 { 3119 if (ImGui::MenuItem("Some menu item")) {} 3120 ImGui::EndMenu(); 3121 } 3122 ImGui::EndMenuBar(); 3123 } 3124 ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); 3125 3126 // Testing behavior of widgets stacking their own regular popups over the modal. 1608 3127 static int item = 1; 3128 static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; 1609 3129 ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); 1610 static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; 1611 ImGui::ColorEdit4("color", color); // This is to test behavior of stacked regular popups over a modal 3130 ImGui::ColorEdit4("color", color); 1612 3131 1613 3132 if (ImGui::Button("Add another modal..")) 1614 ImGui::OpenPopup("Stacked 2"); 1615 if (ImGui::BeginPopupModal("Stacked 2")) 1616 { 1617 ImGui::Text("Hello from Stacked The Second!"); 1618 if (ImGui::Button("Close")) 1619 ImGui::CloseCurrentPopup(); 1620 ImGui::EndPopup(); 3133 ImGui::OpenPopup("Stacked 2"); 3134 3135 // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which 3136 // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value 3137 // of the bool actually doesn't matter here. 3138 bool unused_open = true; 3139 if (ImGui::BeginPopupModal("Stacked 2", &unused_open)) 3140 { 3141 ImGui::Text("Hello from Stacked The Second!"); 3142 if (ImGui::Button("Close")) 3143 ImGui::CloseCurrentPopup(); 3144 ImGui::EndPopup(); 1621 3145 } 1622 3146 1623 3147 if (ImGui::Button("Close")) 1624 ImGui::CloseCurrentPopup();3148 ImGui::CloseCurrentPopup(); 1625 3149 ImGui::EndPopup(); 1626 } 1627 1628 ImGui::TreePop(); 1629 } 1630 1631 if (ImGui::TreeNode("Menus inside a regular window")) 1632 { 1633 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); 1634 ImGui::Separator(); 1635 // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above. 1636 // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here 1637 // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus. 1638 ImGui::PushID("foo"); 1639 ImGui::MenuItem("Menu item", "CTRL+M"); 1640 if (ImGui::BeginMenu("Menu inside a regular window")) 1641 { 3150 } 3151 3152 ImGui::TreePop(); 3153 } 3154 3155 if (ImGui::TreeNode("Menus inside a regular window")) 3156 { 3157 ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!"); 3158 ImGui::Separator(); 3159 3160 // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the 3161 // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block 3162 // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would 3163 // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, 3164 // which is the desired behavior for regular menus. 3165 ImGui::PushID("foo"); 3166 ImGui::MenuItem("Menu item", "CTRL+M"); 3167 if (ImGui::BeginMenu("Menu inside a regular window")) 3168 { 1642 3169 ShowExampleMenuFile(); 1643 3170 ImGui::EndMenu(); 1644 } 1645 ImGui::PopID(); 1646 ImGui::Separator(); 1647 ImGui::TreePop(); 1648 } 1649 } 1650 1651 if (ImGui::CollapsingHeader("Columns")) 1652 { 1653 ImGui::PushID("Columns"); 1654 1655 // Basic columns 1656 if (ImGui::TreeNode("Basic")) 1657 { 1658 ImGui::Text("Without border:"); 1659 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border 1660 ImGui::Separator(); 1661 for (int n = 0; n < 14; n++) 1662 { 3171 } 3172 ImGui::PopID(); 3173 ImGui::Separator(); 3174 ImGui::TreePop(); 3175 } 3176 } 3177 3178 static void ShowDemoWindowColumns() 3179 { 3180 if (!ImGui::CollapsingHeader("Columns")) 3181 return; 3182 3183 ImGui::PushID("Columns"); 3184 3185 static bool disable_indent = false; 3186 ImGui::Checkbox("Disable tree indentation", &disable_indent); 3187 ImGui::SameLine(); 3188 HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width."); 3189 if (disable_indent) 3190 ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); 3191 3192 // Basic columns 3193 if (ImGui::TreeNode("Basic")) 3194 { 3195 ImGui::Text("Without border:"); 3196 ImGui::Columns(3, "mycolumns3", false); // 3-ways, no border 3197 ImGui::Separator(); 3198 for (int n = 0; n < 14; n++) 3199 { 1663 3200 char label[32]; 1664 3201 sprintf(label, "Item %d", n); 1665 3202 if (ImGui::Selectable(label)) {} 1666 //if (ImGui::Button(label, ImVec2(- 1,0))) {}3203 //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {} 1667 3204 ImGui::NextColumn(); 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 3205 } 3206 ImGui::Columns(1); 3207 ImGui::Separator(); 3208 3209 ImGui::Text("With border:"); 3210 ImGui::Columns(4, "mycolumns"); // 4-ways, with border 3211 ImGui::Separator(); 3212 ImGui::Text("ID"); ImGui::NextColumn(); 3213 ImGui::Text("Name"); ImGui::NextColumn(); 3214 ImGui::Text("Path"); ImGui::NextColumn(); 3215 ImGui::Text("Hovered"); ImGui::NextColumn(); 3216 ImGui::Separator(); 3217 const char* names[3] = { "One", "Two", "Three" }; 3218 const char* paths[3] = { "/path/one", "/path/two", "/path/three" }; 3219 static int selected = -1; 3220 for (int i = 0; i < 3; i++) 3221 { 1685 3222 char label[32]; 1686 3223 sprintf(label, "%04d", i); 1687 3224 if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns)) 1688 selected = i;3225 selected = i; 1689 3226 bool hovered = ImGui::IsItemHovered(); 1690 3227 ImGui::NextColumn(); … … 1692 3229 ImGui::Text(paths[i]); ImGui::NextColumn(); 1693 3230 ImGui::Text("%d", hovered); ImGui::NextColumn(); 1694 } 1695 ImGui::Columns(1); 1696 ImGui::Separator(); 1697 ImGui::TreePop(); 1698 } 1699 1700 // Create multiple items in a same cell before switching to next column 1701 if (ImGui::TreeNode("Mixed items")) 1702 { 1703 ImGui::Columns(3, "mixed"); 1704 ImGui::Separator(); 1705 1706 ImGui::Text("Hello"); 1707 ImGui::Button("Banana"); 1708 ImGui::NextColumn(); 1709 1710 ImGui::Text("ImGui"); 1711 ImGui::Button("Apple"); 1712 static float foo = 1.0f; 1713 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); 1714 ImGui::Text("An extra line here."); 1715 ImGui::NextColumn(); 1716 1717 ImGui::Text("Sailor"); 1718 ImGui::Button("Corniflower"); 1719 static float bar = 1.0f; 1720 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); 1721 ImGui::NextColumn(); 1722 1723 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 1724 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 1725 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 1726 ImGui::Columns(1); 1727 ImGui::Separator(); 1728 ImGui::TreePop(); 1729 } 1730 1731 // Word wrapping 1732 if (ImGui::TreeNode("Word-wrapping")) 1733 { 1734 ImGui::Columns(2, "word-wrapping"); 1735 ImGui::Separator(); 1736 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 1737 ImGui::TextWrapped("Hello Left"); 1738 ImGui::NextColumn(); 1739 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 1740 ImGui::TextWrapped("Hello Right"); 1741 ImGui::Columns(1); 1742 ImGui::Separator(); 1743 ImGui::TreePop(); 1744 } 1745 1746 if (ImGui::TreeNode("Borders")) 1747 { 1748 // NB: Future columns API should allow automatic horizontal borders. 1749 static bool h_borders = true; 1750 static bool v_borders = true; 1751 ImGui::Checkbox("horizontal", &h_borders); 1752 ImGui::SameLine(); 1753 ImGui::Checkbox("vertical", &v_borders); 1754 ImGui::Columns(4, NULL, v_borders); 1755 for (int i = 0; i < 4 * 3; i++) 1756 { 3231 } 3232 ImGui::Columns(1); 3233 ImGui::Separator(); 3234 ImGui::TreePop(); 3235 } 3236 3237 if (ImGui::TreeNode("Borders")) 3238 { 3239 // NB: Future columns API should allow automatic horizontal borders. 3240 static bool h_borders = true; 3241 static bool v_borders = true; 3242 static int columns_count = 4; 3243 const int lines_count = 3; 3244 ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); 3245 ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns"); 3246 if (columns_count < 2) 3247 columns_count = 2; 3248 ImGui::SameLine(); 3249 ImGui::Checkbox("horizontal", &h_borders); 3250 ImGui::SameLine(); 3251 ImGui::Checkbox("vertical", &v_borders); 3252 ImGui::Columns(columns_count, NULL, v_borders); 3253 for (int i = 0; i < columns_count * lines_count; i++) 3254 { 1757 3255 if (h_borders && ImGui::GetColumnIndex() == 0) 1758 ImGui::Separator();3256 ImGui::Separator(); 1759 3257 ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); 1760 ImGui::Text("Width %.2f\nOffset %.2f", ImGui::GetColumnWidth(), ImGui::GetColumnOffset()); 3258 ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); 3259 ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); 3260 ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); 3261 ImGui::Text("Long text that is likely to clip"); 3262 ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); 1761 3263 ImGui::NextColumn(); 1762 1763 1764 3264 } 3265 ImGui::Columns(1); 3266 if (h_borders) 1765 3267 ImGui::Separator(); 1766 ImGui::TreePop(); 1767 } 1768 1769 // Scrolling columns 1770 /* 1771 if (ImGui::TreeNode("Vertical Scrolling")) 1772 { 1773 ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); 1774 ImGui::Columns(3); 1775 ImGui::Text("ID"); ImGui::NextColumn(); 1776 ImGui::Text("Name"); ImGui::NextColumn(); 1777 ImGui::Text("Path"); ImGui::NextColumn(); 1778 ImGui::Columns(1); 1779 ImGui::Separator(); 1780 ImGui::EndChild(); 1781 ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); 1782 ImGui::Columns(3); 1783 for (int i = 0; i < 10; i++) 1784 { 1785 ImGui::Text("%04d", i); ImGui::NextColumn(); 1786 ImGui::Text("Foobar"); ImGui::NextColumn(); 1787 ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); 1788 } 1789 ImGui::Columns(1); 1790 ImGui::EndChild(); 1791 ImGui::TreePop(); 1792 } 1793 */ 1794 1795 if (ImGui::TreeNode("Horizontal Scrolling")) 1796 { 1797 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); 1798 ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar); 1799 ImGui::Columns(10); 1800 int ITEMS_COUNT = 2000; 1801 ImGuiListClipper clipper(ITEMS_COUNT); // Also demonstrate using the clipper for large list 1802 while (clipper.Step()) 1803 { 3268 ImGui::TreePop(); 3269 } 3270 3271 // Create multiple items in a same cell before switching to next column 3272 if (ImGui::TreeNode("Mixed items")) 3273 { 3274 ImGui::Columns(3, "mixed"); 3275 ImGui::Separator(); 3276 3277 ImGui::Text("Hello"); 3278 ImGui::Button("Banana"); 3279 ImGui::NextColumn(); 3280 3281 ImGui::Text("ImGui"); 3282 ImGui::Button("Apple"); 3283 static float foo = 1.0f; 3284 ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f"); 3285 ImGui::Text("An extra line here."); 3286 ImGui::NextColumn(); 3287 3288 ImGui::Text("Sailor"); 3289 ImGui::Button("Corniflower"); 3290 static float bar = 1.0f; 3291 ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f"); 3292 ImGui::NextColumn(); 3293 3294 if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 3295 if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 3296 if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn(); 3297 ImGui::Columns(1); 3298 ImGui::Separator(); 3299 ImGui::TreePop(); 3300 } 3301 3302 // Word wrapping 3303 if (ImGui::TreeNode("Word-wrapping")) 3304 { 3305 ImGui::Columns(2, "word-wrapping"); 3306 ImGui::Separator(); 3307 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 3308 ImGui::TextWrapped("Hello Left"); 3309 ImGui::NextColumn(); 3310 ImGui::TextWrapped("The quick brown fox jumps over the lazy dog."); 3311 ImGui::TextWrapped("Hello Right"); 3312 ImGui::Columns(1); 3313 ImGui::Separator(); 3314 ImGui::TreePop(); 3315 } 3316 3317 // Scrolling columns 3318 /* 3319 if (ImGui::TreeNode("Vertical Scrolling")) 3320 { 3321 ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)); 3322 ImGui::Columns(3); 3323 ImGui::Text("ID"); ImGui::NextColumn(); 3324 ImGui::Text("Name"); ImGui::NextColumn(); 3325 ImGui::Text("Path"); ImGui::NextColumn(); 3326 ImGui::Columns(1); 3327 ImGui::Separator(); 3328 ImGui::EndChild(); 3329 ImGui::BeginChild("##scrollingregion", ImVec2(0, 60)); 3330 ImGui::Columns(3); 3331 for (int i = 0; i < 10; i++) 3332 { 3333 ImGui::Text("%04d", i); ImGui::NextColumn(); 3334 ImGui::Text("Foobar"); ImGui::NextColumn(); 3335 ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn(); 3336 } 3337 ImGui::Columns(1); 3338 ImGui::EndChild(); 3339 ImGui::TreePop(); 3340 } 3341 */ 3342 3343 if (ImGui::TreeNode("Horizontal Scrolling")) 3344 { 3345 ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); 3346 ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); 3347 ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); 3348 ImGui::Columns(10); 3349 int ITEMS_COUNT = 2000; 3350 ImGuiListClipper clipper; // Also demonstrate using the clipper for large list 3351 clipper.Begin(ITEMS_COUNT); 3352 while (clipper.Step()) 3353 { 1804 3354 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 1805 for (int j = 0; j < 10; j++) 1806 { 1807 ImGui::Text("Line %d Column %d...", i, j); 1808 ImGui::NextColumn(); 1809 } 1810 } 1811 ImGui::Columns(1); 1812 ImGui::EndChild(); 1813 ImGui::TreePop(); 1814 } 1815 1816 bool node_open = ImGui::TreeNode("Tree within single cell"); 1817 ImGui::SameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell. There's no storage of state per-cell."); 1818 if (node_open) 1819 { 1820 ImGui::Columns(2, "tree items"); 1821 ImGui::Separator(); 1822 if (ImGui::TreeNode("Hello")) { ImGui::BulletText("Sailor"); ImGui::TreePop(); } ImGui::NextColumn(); 1823 if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Marin"); ImGui::TreePop(); } ImGui::NextColumn(); 1824 ImGui::Columns(1); 1825 ImGui::Separator(); 1826 ImGui::TreePop(); 1827 } 1828 ImGui::PopID(); 1829 } 1830 1831 if (ImGui::CollapsingHeader("Filtering")) 1832 { 1833 static ImGuiTextFilter filter; 1834 ImGui::Text("Filter usage:\n" 1835 " \"\" display all lines\n" 1836 " \"xxx\" display lines containing \"xxx\"\n" 1837 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" 1838 " \"-xxx\" hide lines containing \"xxx\""); 1839 filter.Draw(); 1840 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; 1841 for (int i = 0; i < IM_ARRAYSIZE(lines); i++) 1842 if (filter.PassFilter(lines[i])) 1843 ImGui::BulletText("%s", lines[i]); 1844 } 1845 1846 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) 1847 { 1848 ImGuiIO& io = ImGui::GetIO(); 1849 1850 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); 1851 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); 1852 ImGui::Text("WantTextInput: %d", io.WantTextInput); 1853 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); 1854 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); 1855 1856 ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); 1857 ImGui::SameLine(); ShowHelpMarker("Instruct ImGui to render a mouse cursor for you in software. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); 1858 1859 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); 1860 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); 1861 ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); 1862 ImGui::SameLine(); ShowHelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); 1863 ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); 1864 ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility."); 1865 1866 if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) 1867 { 1868 if (ImGui::IsMousePosValid()) 1869 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); 1870 else 1871 ImGui::Text("Mouse pos: <INVALID>"); 1872 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); 1873 ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } 1874 ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 1875 ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 1876 ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 1877 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); 1878 1879 ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]); } 1880 ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } 1881 ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } 1882 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); 1883 1884 ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } 1885 ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } 1886 ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } 1887 1888 ImGui::Button("Hovering me sets the\nkeyboard capture flag"); 1889 if (ImGui::IsItemHovered()) 1890 ImGui::CaptureKeyboardFromApp(true); 1891 ImGui::SameLine(); 1892 ImGui::Button("Holding me clears the\nthe keyboard capture flag"); 1893 if (ImGui::IsItemActive()) 1894 ImGui::CaptureKeyboardFromApp(false); 1895 1896 ImGui::TreePop(); 1897 } 1898 1899 if (ImGui::TreeNode("Tabbing")) 1900 { 1901 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); 1902 static char buf[32] = "dummy"; 1903 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 1904 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 1905 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); 1906 ImGui::PushAllowKeyboardFocus(false); 1907 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); 1908 //ImGui::SameLine(); ShowHelperMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets."); 1909 ImGui::PopAllowKeyboardFocus(); 1910 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); 1911 ImGui::TreePop(); 1912 } 1913 1914 if (ImGui::TreeNode("Focus from code")) 1915 { 1916 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); 1917 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); 1918 bool focus_3 = ImGui::Button("Focus on 3"); 1919 int has_focus = 0; 1920 static char buf[128] = "click on a button to set focus"; 1921 1922 if (focus_1) ImGui::SetKeyboardFocusHere(); 1923 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 1924 if (ImGui::IsItemActive()) has_focus = 1; 1925 1926 if (focus_2) ImGui::SetKeyboardFocusHere(); 1927 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 1928 if (ImGui::IsItemActive()) has_focus = 2; 1929 1930 ImGui::PushAllowKeyboardFocus(false); 1931 if (focus_3) ImGui::SetKeyboardFocusHere(); 1932 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); 1933 if (ImGui::IsItemActive()) has_focus = 3; 1934 ImGui::PopAllowKeyboardFocus(); 1935 1936 if (has_focus) 1937 ImGui::Text("Item with focus: %d", has_focus); 1938 else 1939 ImGui::Text("Item with focus: <none>"); 1940 1941 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item 1942 static float f3[3] = { 0.0f, 0.0f, 0.0f }; 1943 int focus_ahead = -1; 1944 if (ImGui::Button("Focus on X")) focus_ahead = 0; ImGui::SameLine(); 1945 if (ImGui::Button("Focus on Y")) focus_ahead = 1; ImGui::SameLine(); 1946 if (ImGui::Button("Focus on Z")) focus_ahead = 2; 1947 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); 1948 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); 1949 1950 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); 1951 ImGui::TreePop(); 1952 } 1953 1954 if (ImGui::TreeNode("Focused & Hovered Test")) 1955 { 1956 static bool embed_all_inside_a_child_window = false; 1957 ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); 1958 if (embed_all_inside_a_child_window) 1959 ImGui::BeginChild("embeddingchild", ImVec2(0, ImGui::GetFontSize() * 25), true); 1960 1961 // Testing IsWindowFocused() function with its various flags (note that the flags can be combined) 1962 ImGui::BulletText( 1963 "IsWindowFocused() = %d\n" 1964 "IsWindowFocused(_ChildWindows) = %d\n" 1965 "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" 1966 "IsWindowFocused(_RootWindow) = %d\n" 1967 "IsWindowFocused(_AnyWindow) = %d\n", 1968 ImGui::IsWindowFocused(), 1969 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), 1970 ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), 1971 ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), 1972 ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); 1973 1974 // Testing IsWindowHovered() function with its various flags (note that the flags can be combined) 1975 ImGui::BulletText( 1976 "IsWindowHovered() = %d\n" 1977 "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" 1978 "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1979 "IsWindowHovered(_ChildWindows) = %d\n" 1980 "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" 1981 "IsWindowHovered(_RootWindow) = %d\n" 1982 "IsWindowHovered(_AnyWindow) = %d\n", 1983 ImGui::IsWindowHovered(), 1984 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 1985 ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 1986 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), 1987 ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), 1988 ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), 1989 ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); 1990 1991 // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code) 1992 ImGui::Button("ITEM"); 1993 ImGui::BulletText( 1994 "IsItemHovered() = %d\n" 1995 "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" 1996 "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" 1997 "IsItemHovered(_AllowWhenOverlapped) = %d\n" 1998 "IsItemhovered(_RectOnly) = %d\n", 1999 ImGui::IsItemHovered(), 2000 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), 2001 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), 2002 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped), 2003 ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)); 2004 2005 ImGui::BeginChild("child", ImVec2(0, 50), true); 2006 ImGui::Text("This is another child window for testing IsWindowHovered() flags."); 2007 ImGui::EndChild(); 2008 2009 if (embed_all_inside_a_child_window) 2010 EndChild(); 2011 2012 ImGui::TreePop(); 2013 } 2014 2015 if (ImGui::TreeNode("Dragging")) 2016 { 2017 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); 2018 for (int button = 0; button < 3; button++) 2019 ImGui::Text("IsMouseDragging(%d):\n w/ default threshold: %d,\n w/ zero threshold: %d\n w/ large threshold: %d", 2020 button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f)); 2021 ImGui::Button("Drag Me"); 2022 if (ImGui::IsItemActive()) 2023 { 2024 // Draw a line between the button and the mouse cursor 2025 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2026 draw_list->PushClipRectFullScreen(); 2027 draw_list->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); 2028 draw_list->PopClipRect(); 2029 2030 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold) 2031 // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta() 3355 for (int j = 0; j < 10; j++) 3356 { 3357 ImGui::Text("Line %d Column %d...", i, j); 3358 ImGui::NextColumn(); 3359 } 3360 } 3361 ImGui::Columns(1); 3362 ImGui::EndChild(); 3363 ImGui::TreePop(); 3364 } 3365 3366 if (ImGui::TreeNode("Tree")) 3367 { 3368 ImGui::Columns(2, "tree", true); 3369 for (int x = 0; x < 3; x++) 3370 { 3371 bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x); 3372 ImGui::NextColumn(); 3373 ImGui::Text("Node contents"); 3374 ImGui::NextColumn(); 3375 if (open1) 3376 { 3377 for (int y = 0; y < 3; y++) 3378 { 3379 bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y); 3380 ImGui::NextColumn(); 3381 ImGui::Text("Node contents"); 3382 if (open2) 3383 { 3384 ImGui::Text("Even more contents"); 3385 if (ImGui::TreeNode("Tree in column")) 3386 { 3387 ImGui::Text("The quick brown fox jumps over the lazy dog"); 3388 ImGui::TreePop(); 3389 } 3390 } 3391 ImGui::NextColumn(); 3392 if (open2) 3393 ImGui::TreePop(); 3394 } 3395 ImGui::TreePop(); 3396 } 3397 } 3398 ImGui::Columns(1); 3399 ImGui::TreePop(); 3400 } 3401 3402 if (disable_indent) 3403 ImGui::PopStyleVar(); 3404 ImGui::PopID(); 3405 } 3406 3407 static void ShowDemoWindowMisc() 3408 { 3409 if (ImGui::CollapsingHeader("Filtering")) 3410 { 3411 // Helper class to easy setup a text filter. 3412 // You may want to implement a more feature-full filtering scheme in your own application. 3413 static ImGuiTextFilter filter; 3414 ImGui::Text("Filter usage:\n" 3415 " \"\" display all lines\n" 3416 " \"xxx\" display lines containing \"xxx\"\n" 3417 " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" 3418 " \"-xxx\" hide lines containing \"xxx\""); 3419 filter.Draw(); 3420 const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; 3421 for (int i = 0; i < IM_ARRAYSIZE(lines); i++) 3422 if (filter.PassFilter(lines[i])) 3423 ImGui::BulletText("%s", lines[i]); 3424 } 3425 3426 if (ImGui::CollapsingHeader("Inputs, Navigation & Focus")) 3427 { 3428 ImGuiIO& io = ImGui::GetIO(); 3429 3430 // Display ImGuiIO output flags 3431 ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); 3432 ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); 3433 ImGui::Text("WantTextInput: %d", io.WantTextInput); 3434 ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); 3435 ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible); 3436 3437 // Display Keyboard/Mouse state 3438 if (ImGui::TreeNode("Keyboard, Mouse & Navigation State")) 3439 { 3440 if (ImGui::IsMousePosValid()) 3441 ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); 3442 else 3443 ImGui::Text("Mouse pos: <INVALID>"); 3444 ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); 3445 ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } 3446 ImGui::Text("Mouse clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 3447 ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 3448 ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } 3449 ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); 3450 3451 ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); } 3452 ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } 3453 ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); } 3454 ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); 3455 ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. 3456 3457 ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); } 3458 ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } 3459 ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); } 3460 3461 ImGui::Button("Hovering me sets the\nkeyboard capture flag"); 3462 if (ImGui::IsItemHovered()) 3463 ImGui::CaptureKeyboardFromApp(true); 3464 ImGui::SameLine(); 3465 ImGui::Button("Holding me clears the\nthe keyboard capture flag"); 3466 if (ImGui::IsItemActive()) 3467 ImGui::CaptureKeyboardFromApp(false); 3468 3469 ImGui::TreePop(); 3470 } 3471 3472 if (ImGui::TreeNode("Tabbing")) 3473 { 3474 ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields."); 3475 static char buf[32] = "hello"; 3476 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 3477 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 3478 ImGui::InputText("3", buf, IM_ARRAYSIZE(buf)); 3479 ImGui::PushAllowKeyboardFocus(false); 3480 ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf)); 3481 //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool) to disable tabbing through certain widgets."); 3482 ImGui::PopAllowKeyboardFocus(); 3483 ImGui::InputText("5", buf, IM_ARRAYSIZE(buf)); 3484 ImGui::TreePop(); 3485 } 3486 3487 if (ImGui::TreeNode("Focus from code")) 3488 { 3489 bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine(); 3490 bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine(); 3491 bool focus_3 = ImGui::Button("Focus on 3"); 3492 int has_focus = 0; 3493 static char buf[128] = "click on a button to set focus"; 3494 3495 if (focus_1) ImGui::SetKeyboardFocusHere(); 3496 ImGui::InputText("1", buf, IM_ARRAYSIZE(buf)); 3497 if (ImGui::IsItemActive()) has_focus = 1; 3498 3499 if (focus_2) ImGui::SetKeyboardFocusHere(); 3500 ImGui::InputText("2", buf, IM_ARRAYSIZE(buf)); 3501 if (ImGui::IsItemActive()) has_focus = 2; 3502 3503 ImGui::PushAllowKeyboardFocus(false); 3504 if (focus_3) ImGui::SetKeyboardFocusHere(); 3505 ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf)); 3506 if (ImGui::IsItemActive()) has_focus = 3; 3507 ImGui::PopAllowKeyboardFocus(); 3508 3509 if (has_focus) 3510 ImGui::Text("Item with focus: %d", has_focus); 3511 else 3512 ImGui::Text("Item with focus: <none>"); 3513 3514 // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item 3515 static float f3[3] = { 0.0f, 0.0f, 0.0f }; 3516 int focus_ahead = -1; 3517 if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine(); 3518 if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine(); 3519 if (ImGui::Button("Focus on Z")) { focus_ahead = 2; } 3520 if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead); 3521 ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f); 3522 3523 ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code."); 3524 ImGui::TreePop(); 3525 } 3526 3527 if (ImGui::TreeNode("Dragging")) 3528 { 3529 ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget."); 3530 for (int button = 0; button < 3; button++) 3531 { 3532 ImGui::Text("IsMouseDragging(%d):", button); 3533 ImGui::Text(" w/ default threshold: %d,", ImGui::IsMouseDragging(button)); 3534 ImGui::Text(" w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f)); 3535 ImGui::Text(" w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f)); 3536 } 3537 3538 ImGui::Button("Drag Me"); 3539 if (ImGui::IsItemActive()) 3540 ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor 3541 3542 // Drag operations gets "unlocked" when the mouse has moved past a certain threshold 3543 // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher 3544 // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta(). 2032 3545 ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f); 2033 3546 ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0); 2034 3547 ImVec2 mouse_delta = io.MouseDelta; 2035 ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y); 2036 } 2037 ImGui::TreePop(); 2038 } 2039 2040 if (ImGui::TreeNode("Mouse cursors")) 2041 { 2042 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE" }; 2043 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); 2044 2045 ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]); 2046 ImGui::Text("Hover to see mouse cursors:"); 2047 ImGui::SameLine(); ShowHelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it."); 2048 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) 2049 { 2050 char label[32]; 2051 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); 2052 ImGui::Bullet(); ImGui::Selectable(label, false); 2053 if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) 2054 ImGui::SetMouseCursor(i); 2055 } 2056 ImGui::TreePop(); 2057 } 2058 } 2059 2060 ImGui::End(); 3548 ImGui::Text("GetMouseDragDelta(0):"); 3549 ImGui::Text(" w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y); 3550 ImGui::Text(" w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y); 3551 ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y); 3552 ImGui::TreePop(); 3553 } 3554 3555 if (ImGui::TreeNode("Mouse cursors")) 3556 { 3557 const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; 3558 IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); 3559 3560 ImGuiMouseCursor current = ImGui::GetMouseCursor(); 3561 ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); 3562 ImGui::Text("Hover to see mouse cursors:"); 3563 ImGui::SameLine(); HelpMarker( 3564 "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. " 3565 "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, " 3566 "otherwise your backend needs to handle it."); 3567 for (int i = 0; i < ImGuiMouseCursor_COUNT; i++) 3568 { 3569 char label[32]; 3570 sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); 3571 ImGui::Bullet(); ImGui::Selectable(label, false); 3572 if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) 3573 ImGui::SetMouseCursor(i); 3574 } 3575 ImGui::TreePop(); 3576 } 3577 } 2061 3578 } 2062 3579 3580 //----------------------------------------------------------------------------- 3581 // [SECTION] About Window / ShowAboutWindow() 3582 // Access from Dear ImGui Demo -> Tools -> About 3583 //----------------------------------------------------------------------------- 3584 3585 void ImGui::ShowAboutWindow(bool* p_open) 3586 { 3587 if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 3588 { 3589 ImGui::End(); 3590 return; 3591 } 3592 ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); 3593 ImGui::Separator(); 3594 ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); 3595 ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); 3596 3597 static bool show_config_info = false; 3598 ImGui::Checkbox("Config/Build Information", &show_config_info); 3599 if (show_config_info) 3600 { 3601 ImGuiIO& io = ImGui::GetIO(); 3602 ImGuiStyle& style = ImGui::GetStyle(); 3603 3604 bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); 3605 ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); 3606 ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); 3607 if (copy_to_clipboard) 3608 { 3609 ImGui::LogToClipboard(); 3610 ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub 3611 } 3612 3613 ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); 3614 ImGui::Separator(); 3615 ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert)); 3616 ImGui::Text("define: __cplusplus=%d", (int)__cplusplus); 3617 #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS 3618 ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); 3619 #endif 3620 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS 3621 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); 3622 #endif 3623 #ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS 3624 ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS"); 3625 #endif 3626 #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS 3627 ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); 3628 #endif 3629 #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS 3630 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); 3631 #endif 3632 #ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS 3633 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); 3634 #endif 3635 #ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 3636 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); 3637 #endif 3638 #ifdef IMGUI_DISABLE_FILE_FUNCTIONS 3639 ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); 3640 #endif 3641 #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS 3642 ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); 3643 #endif 3644 #ifdef IMGUI_USE_BGRA_PACKED_COLOR 3645 ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR"); 3646 #endif 3647 #ifdef _WIN32 3648 ImGui::Text("define: _WIN32"); 3649 #endif 3650 #ifdef _WIN64 3651 ImGui::Text("define: _WIN64"); 3652 #endif 3653 #ifdef __linux__ 3654 ImGui::Text("define: __linux__"); 3655 #endif 3656 #ifdef __APPLE__ 3657 ImGui::Text("define: __APPLE__"); 3658 #endif 3659 #ifdef _MSC_VER 3660 ImGui::Text("define: _MSC_VER=%d", _MSC_VER); 3661 #endif 3662 #ifdef __MINGW32__ 3663 ImGui::Text("define: __MINGW32__"); 3664 #endif 3665 #ifdef __MINGW64__ 3666 ImGui::Text("define: __MINGW64__"); 3667 #endif 3668 #ifdef __GNUC__ 3669 ImGui::Text("define: __GNUC__=%d", (int)__GNUC__); 3670 #endif 3671 #ifdef __clang_version__ 3672 ImGui::Text("define: __clang_version__=%s", __clang_version__); 3673 #endif 3674 ImGui::Separator(); 3675 ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL"); 3676 ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL"); 3677 ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); 3678 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); 3679 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); 3680 if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); 3681 if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); 3682 if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); 3683 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); 3684 if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); 3685 if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); 3686 if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); 3687 if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); 3688 if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); 3689 if (io.ConfigWindowsMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer); 3690 ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); 3691 if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); 3692 if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); 3693 if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); 3694 if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); 3695 ImGui::Separator(); 3696 ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); 3697 ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); 3698 ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); 3699 ImGui::Separator(); 3700 ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y); 3701 ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize); 3702 ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y); 3703 ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding); 3704 ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize); 3705 ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y); 3706 ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y); 3707 3708 if (copy_to_clipboard) 3709 { 3710 ImGui::LogText("\n```\n"); 3711 ImGui::LogFinish(); 3712 } 3713 ImGui::EndChildFrame(); 3714 } 3715 ImGui::End(); 3716 } 3717 3718 //----------------------------------------------------------------------------- 3719 // [SECTION] Style Editor / ShowStyleEditor() 3720 //----------------------------------------------------------------------------- 3721 // - ShowStyleSelector() 3722 // - ShowFontSelector() 3723 // - ShowStyleEditor() 3724 //----------------------------------------------------------------------------- 3725 2063 3726 // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. 2064 // Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally. 3727 // Here we use the simplified Combo() api that packs items into a single literal string. 3728 // Useful for quick combo boxes where the choices are known locally. 2065 3729 bool ImGui::ShowStyleSelector(const char* label) 2066 3730 { 2067 static int style_idx = -1;2068 if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))2069 {2070 switch (style_idx)2071 {2072 case 0: ImGui::StyleColorsClassic(); break;2073 case 1: ImGui::StyleColorsDark(); break;2074 case 2: ImGui::StyleColorsLight(); break;2075 }2076 return true;2077 }2078 return false;3731 static int style_idx = -1; 3732 if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0")) 3733 { 3734 switch (style_idx) 3735 { 3736 case 0: ImGui::StyleColorsClassic(); break; 3737 case 1: ImGui::StyleColorsDark(); break; 3738 case 2: ImGui::StyleColorsLight(); break; 3739 } 3740 return true; 3741 } 3742 return false; 2079 3743 } 2080 3744 … … 2083 3747 void ImGui::ShowFontSelector(const char* label) 2084 3748 { 2085 ImGuiIO& io = ImGui::GetIO(); 2086 ImFont* font_current = ImGui::GetFont(); 2087 if (ImGui::BeginCombo(label, font_current->GetDebugName())) 2088 { 2089 for (int n = 0; n < io.Fonts->Fonts.Size; n++) 2090 if (ImGui::Selectable(io.Fonts->Fonts[n]->GetDebugName(), io.Fonts->Fonts[n] == font_current)) 2091 io.FontDefault = io.Fonts->Fonts[n]; 2092 ImGui::EndCombo(); 2093 } 2094 ImGui::SameLine(); 2095 ShowHelpMarker( 2096 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" 2097 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" 2098 "- Read FAQ and documentation in misc/fonts/ for more details.\n" 2099 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); 3749 ImGuiIO& io = ImGui::GetIO(); 3750 ImFont* font_current = ImGui::GetFont(); 3751 if (ImGui::BeginCombo(label, font_current->GetDebugName())) 3752 { 3753 for (int n = 0; n < io.Fonts->Fonts.Size; n++) 3754 { 3755 ImFont* font = io.Fonts->Fonts[n]; 3756 ImGui::PushID((void*)font); 3757 if (ImGui::Selectable(font->GetDebugName(), font == font_current)) 3758 io.FontDefault = font; 3759 ImGui::PopID(); 3760 } 3761 ImGui::EndCombo(); 3762 } 3763 ImGui::SameLine(); 3764 HelpMarker( 3765 "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" 3766 "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" 3767 "- Read FAQ and docs/FONTS.md for more details.\n" 3768 "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); 3769 } 3770 3771 // [Internal] Display details for a single font, called by ShowStyleEditor(). 3772 static void NodeFont(ImFont* font) 3773 { 3774 ImGuiIO& io = ImGui::GetIO(); 3775 ImGuiStyle& style = ImGui::GetStyle(); 3776 bool font_details_opened = ImGui::TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", 3777 font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); 3778 ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } 3779 if (!font_details_opened) 3780 return; 3781 3782 ImGui::PushFont(font); 3783 ImGui::Text("The quick brown fox jumps over the lazy dog"); 3784 ImGui::PopFont(); 3785 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font 3786 ImGui::SameLine(); HelpMarker( 3787 "Note than the default embedded font is NOT meant to be scaled.\n\n" 3788 "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " 3789 "You may oversample them to get some flexibility with scaling. " 3790 "You can also render at multiple sizes and select which one to use at runtime.\n\n" 3791 "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); 3792 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); 3793 ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar); 3794 ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar); 3795 const int surface_sqrt = (int)sqrtf((float)font->MetricsTotalSurface); 3796 ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); 3797 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) 3798 if (font->ConfigData) 3799 if (const ImFontConfig* cfg = &font->ConfigData[config_i]) 3800 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", 3801 config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); 3802 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) 3803 { 3804 // Display all glyphs of the fonts in separate pages of 256 characters 3805 const ImU32 glyph_col = ImGui::GetColorU32(ImGuiCol_Text); 3806 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) 3807 { 3808 // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) 3809 // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT 3810 // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) 3811 if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) 3812 { 3813 base += 4096 - 256; 3814 continue; 3815 } 3816 3817 int count = 0; 3818 for (unsigned int n = 0; n < 256; n++) 3819 if (font->FindGlyphNoFallback((ImWchar)(base + n))) 3820 count++; 3821 if (count <= 0) 3822 continue; 3823 if (!ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) 3824 continue; 3825 float cell_size = font->FontSize * 1; 3826 float cell_spacing = style.ItemSpacing.y; 3827 ImVec2 base_pos = ImGui::GetCursorScreenPos(); 3828 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 3829 for (unsigned int n = 0; n < 256; n++) 3830 { 3831 // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions 3832 // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. 3833 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); 3834 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); 3835 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); 3836 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); 3837 if (glyph) 3838 font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); 3839 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) 3840 { 3841 ImGui::BeginTooltip(); 3842 ImGui::Text("Codepoint: U+%04X", base + n); 3843 ImGui::Separator(); 3844 ImGui::Text("Visible: %d", glyph->Visible); 3845 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); 3846 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); 3847 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); 3848 ImGui::EndTooltip(); 3849 } 3850 } 3851 ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); 3852 ImGui::TreePop(); 3853 } 3854 ImGui::TreePop(); 3855 } 3856 ImGui::TreePop(); 2100 3857 } 2101 3858 2102 3859 void ImGui::ShowStyleEditor(ImGuiStyle* ref) 2103 3860 { 2104 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference) 2105 ImGuiStyle& style = ImGui::GetStyle(); 2106 static ImGuiStyle ref_saved_style; 2107 2108 // Default to using internal storage as reference 2109 static bool init = true; 2110 if (init && ref == NULL) 2111 ref_saved_style = style; 2112 init = false; 2113 if (ref == NULL) 2114 ref = &ref_saved_style; 2115 2116 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); 2117 2118 if (ImGui::ShowStyleSelector("Colors##Selector")) 2119 ref_saved_style = style; 2120 ImGui::ShowFontSelector("Fonts##Selector"); 2121 2122 // Simplified Settings 2123 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) 2124 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding 2125 { bool window_border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; } 2126 ImGui::SameLine(); 2127 { bool frame_border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; } 2128 ImGui::SameLine(); 2129 { bool popup_border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; } 2130 2131 // Save/Revert button 2132 if (ImGui::Button("Save Ref")) 2133 *ref = ref_saved_style = style; 2134 ImGui::SameLine(); 2135 if (ImGui::Button("Revert Ref")) 2136 style = *ref; 2137 ImGui::SameLine(); 2138 ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere."); 2139 2140 if (ImGui::TreeNode("Rendering")) 2141 { 2142 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); 2143 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); 2144 ImGui::PushItemWidth(100); 2145 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, NULL, 2.0f); 2146 if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f; 2147 ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. 2148 ImGui::PopItemWidth(); 2149 ImGui::TreePop(); 2150 } 2151 2152 if (ImGui::TreeNode("Settings")) 2153 { 2154 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); 2155 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); 2156 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); 2157 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); 2158 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); 2159 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); 2160 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); 2161 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); 2162 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); 2163 ImGui::Text("BorderSize"); 2164 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); 2165 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); 2166 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); 2167 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); 2168 ImGui::Text("Rounding"); 2169 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f"); 2170 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f"); 2171 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); 2172 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); 2173 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); 2174 ImGui::Text("Alignment"); 2175 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); 2176 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content."); 2177 ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); 2178 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); 2179 ImGui::TreePop(); 2180 } 2181 2182 if (ImGui::TreeNode("Colors")) 2183 { 2184 static int output_dest = 0; 2185 static bool output_only_modified = true; 2186 if (ImGui::Button("Export Unsaved")) 2187 { 2188 if (output_dest == 0) 2189 ImGui::LogToClipboard(); 2190 else 2191 ImGui::LogToTTY(); 2192 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); 2193 for (int i = 0; i < ImGuiCol_COUNT; i++) 2194 { 2195 const ImVec4& col = style.Colors[i]; 2196 const char* name = ImGui::GetStyleColorName(i); 2197 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) 2198 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); 2199 } 2200 ImGui::LogFinish(); 2201 } 2202 ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth(); 2203 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); 2204 2205 ImGui::Text("Tip: Left-click on colored square to open color picker,\nRight-click to open edit options menu."); 2206 2207 static ImGuiTextFilter filter; 2208 filter.Draw("Filter colors", 200); 2209 2210 static ImGuiColorEditFlags alpha_flags = 0; 2211 ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine(); 2212 ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine(); 2213 ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf); 2214 2215 ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); 2216 ImGui::PushItemWidth(-160); 2217 for (int i = 0; i < ImGuiCol_COUNT; i++) 2218 { 2219 const char* name = ImGui::GetStyleColorName(i); 2220 if (!filter.PassFilter(name)) 2221 continue; 2222 ImGui::PushID(i); 2223 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); 2224 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) 2225 { 2226 // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons. 2227 // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient! 2228 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i]; 2229 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i]; 2230 } 2231 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); 2232 ImGui::TextUnformatted(name); 2233 ImGui::PopID(); 2234 } 2235 ImGui::PopItemWidth(); 2236 ImGui::EndChild(); 2237 2238 ImGui::TreePop(); 2239 } 2240 2241 bool fonts_opened = ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size); 2242 if (fonts_opened) 2243 { 2244 ImFontAtlas* atlas = ImGui::GetIO().Fonts; 2245 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) 2246 { 2247 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128)); 2248 ImGui::TreePop(); 2249 } 2250 ImGui::PushItemWidth(100); 2251 for (int i = 0; i < atlas->Fonts.Size; i++) 2252 { 2253 ImFont* font = atlas->Fonts[i]; 2254 ImGui::PushID(font); 2255 bool font_details_opened = ImGui::TreeNode(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size); 2256 ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; 2257 if (font_details_opened) 2258 { 2259 ImGui::PushFont(font); 2260 ImGui::Text("The quick brown fox jumps over the lazy dog"); 2261 ImGui::PopFont(); 2262 ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); // Scale only this font 2263 ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, 0); 2264 ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)"); 2265 ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); 2266 ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar); 2267 ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface)); 2268 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) 2269 if (ImFontConfig* cfg = &font->ConfigData[config_i]) 2270 ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH); 2271 if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) 2272 { 2273 // Display all glyphs of the fonts in separate pages of 256 characters 2274 for (int base = 0; base < 0x10000; base += 256) 2275 { 2276 int count = 0; 2277 for (int n = 0; n < 256; n++) 2278 count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0; 2279 if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) 2280 { 2281 float cell_size = font->FontSize * 1; 2282 float cell_spacing = style.ItemSpacing.y; 2283 ImVec2 base_pos = ImGui::GetCursorScreenPos(); 2284 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2285 for (int n = 0; n < 256; n++) 2286 { 2287 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); 2288 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); 2289 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); 2290 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); 2291 font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. 2292 if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) 2293 { 2294 ImGui::BeginTooltip(); 2295 ImGui::Text("Codepoint: U+%04X", base + n); 2296 ImGui::Separator(); 2297 ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); 2298 ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); 2299 ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); 2300 ImGui::EndTooltip(); 2301 } 2302 } 2303 ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); 2304 ImGui::TreePop(); 2305 } 2306 } 2307 ImGui::TreePop(); 2308 } 2309 ImGui::TreePop(); 2310 } 2311 ImGui::PopID(); 2312 } 2313 static float window_scale = 1.0f; 2314 ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale only this window 2315 ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything 2316 ImGui::PopItemWidth(); 2317 ImGui::SetWindowFontScale(window_scale); 2318 ImGui::TreePop(); 2319 } 2320 2321 ImGui::PopItemWidth(); 3861 // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to 3862 // (without a reference style pointer, we will use one compared locally as a reference) 3863 ImGuiStyle& style = ImGui::GetStyle(); 3864 static ImGuiStyle ref_saved_style; 3865 3866 // Default to using internal storage as reference 3867 static bool init = true; 3868 if (init && ref == NULL) 3869 ref_saved_style = style; 3870 init = false; 3871 if (ref == NULL) 3872 ref = &ref_saved_style; 3873 3874 ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); 3875 3876 if (ImGui::ShowStyleSelector("Colors##Selector")) 3877 ref_saved_style = style; 3878 ImGui::ShowFontSelector("Fonts##Selector"); 3879 3880 // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) 3881 if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) 3882 style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding 3883 { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } 3884 ImGui::SameLine(); 3885 { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } 3886 ImGui::SameLine(); 3887 { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } 3888 3889 // Save/Revert button 3890 if (ImGui::Button("Save Ref")) 3891 *ref = ref_saved_style = style; 3892 ImGui::SameLine(); 3893 if (ImGui::Button("Revert Ref")) 3894 style = *ref; 3895 ImGui::SameLine(); 3896 HelpMarker( 3897 "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " 3898 "Use \"Export\" below to save them somewhere."); 3899 3900 ImGui::Separator(); 3901 3902 if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) 3903 { 3904 if (ImGui::BeginTabItem("Sizes")) 3905 { 3906 ImGui::Text("Main"); 3907 ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); 3908 ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); 3909 ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); 3910 ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); 3911 ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); 3912 ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); 3913 ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); 3914 ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); 3915 ImGui::Text("Borders"); 3916 ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); 3917 ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); 3918 ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); 3919 ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); 3920 ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); 3921 ImGui::Text("Rounding"); 3922 ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); 3923 ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); 3924 ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); 3925 ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); 3926 ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); 3927 ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); 3928 ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); 3929 ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); 3930 ImGui::Text("Alignment"); 3931 ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); 3932 int window_menu_button_position = style.WindowMenuButtonPosition + 1; 3933 if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) 3934 style.WindowMenuButtonPosition = window_menu_button_position - 1; 3935 ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); 3936 ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); 3937 ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); 3938 ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); 3939 ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); 3940 ImGui::Text("Safe Area Padding"); 3941 ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); 3942 ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); 3943 ImGui::EndTabItem(); 3944 } 3945 3946 if (ImGui::BeginTabItem("Colors")) 3947 { 3948 static int output_dest = 0; 3949 static bool output_only_modified = true; 3950 if (ImGui::Button("Export")) 3951 { 3952 if (output_dest == 0) 3953 ImGui::LogToClipboard(); 3954 else 3955 ImGui::LogToTTY(); 3956 ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); 3957 for (int i = 0; i < ImGuiCol_COUNT; i++) 3958 { 3959 const ImVec4& col = style.Colors[i]; 3960 const char* name = ImGui::GetStyleColorName(i); 3961 if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) 3962 ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, 3963 name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); 3964 } 3965 ImGui::LogFinish(); 3966 } 3967 ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); 3968 ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); 3969 3970 static ImGuiTextFilter filter; 3971 filter.Draw("Filter colors", ImGui::GetFontSize() * 16); 3972 3973 static ImGuiColorEditFlags alpha_flags = 0; 3974 if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); 3975 if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); 3976 if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); 3977 HelpMarker( 3978 "In the color list:\n" 3979 "Left-click on colored square to open color picker,\n" 3980 "Right-click to open edit options menu."); 3981 3982 ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); 3983 ImGui::PushItemWidth(-160); 3984 for (int i = 0; i < ImGuiCol_COUNT; i++) 3985 { 3986 const char* name = ImGui::GetStyleColorName(i); 3987 if (!filter.PassFilter(name)) 3988 continue; 3989 ImGui::PushID(i); 3990 ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); 3991 if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) 3992 { 3993 // Tips: in a real user application, you may want to merge and use an icon font into the main font, 3994 // so instead of "Save"/"Revert" you'd use icons! 3995 // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! 3996 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } 3997 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } 3998 } 3999 ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); 4000 ImGui::TextUnformatted(name); 4001 ImGui::PopID(); 4002 } 4003 ImGui::PopItemWidth(); 4004 ImGui::EndChild(); 4005 4006 ImGui::EndTabItem(); 4007 } 4008 4009 if (ImGui::BeginTabItem("Fonts")) 4010 { 4011 ImGuiIO& io = ImGui::GetIO(); 4012 ImFontAtlas* atlas = io.Fonts; 4013 HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); 4014 ImGui::PushItemWidth(120); 4015 for (int i = 0; i < atlas->Fonts.Size; i++) 4016 { 4017 ImFont* font = atlas->Fonts[i]; 4018 ImGui::PushID(font); 4019 NodeFont(font); 4020 ImGui::PopID(); 4021 } 4022 if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) 4023 { 4024 ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); 4025 ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); 4026 ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); 4027 ImGui::TreePop(); 4028 } 4029 4030 // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. 4031 // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). 4032 const float MIN_SCALE = 0.3f; 4033 const float MAX_SCALE = 2.0f; 4034 HelpMarker( 4035 "Those are old settings provided for convenience.\n" 4036 "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " 4037 "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" 4038 "Using those settings here will give you poor quality results."); 4039 static float window_scale = 1.0f; 4040 if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window 4041 ImGui::SetWindowFontScale(window_scale); 4042 ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything 4043 ImGui::PopItemWidth(); 4044 4045 ImGui::EndTabItem(); 4046 } 4047 4048 if (ImGui::BeginTabItem("Rendering")) 4049 { 4050 ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); 4051 ImGui::SameLine(); 4052 HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); 4053 4054 ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); 4055 ImGui::SameLine(); 4056 HelpMarker("Faster lines using texture data. Require back-end to render with bilinear filtering (not point/nearest filtering)."); 4057 4058 ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); 4059 ImGui::PushItemWidth(100); 4060 ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); 4061 if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; 4062 4063 // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. 4064 ImGui::DragFloat("Circle Segment Max Error", &style.CircleSegmentMaxError, 0.01f, 0.10f, 10.0f, "%.2f"); 4065 if (ImGui::IsItemActive()) 4066 { 4067 ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); 4068 ImGui::BeginTooltip(); 4069 ImVec2 p = ImGui::GetCursorScreenPos(); 4070 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 4071 float RAD_MIN = 10.0f, RAD_MAX = 80.0f; 4072 float off_x = 10.0f; 4073 for (int n = 0; n < 7; n++) 4074 { 4075 const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (7.0f - 1.0f); 4076 draw_list->AddCircle(ImVec2(p.x + off_x + rad, p.y + RAD_MAX), rad, ImGui::GetColorU32(ImGuiCol_Text), 0); 4077 off_x += 10.0f + rad * 2.0f; 4078 } 4079 ImGui::Dummy(ImVec2(off_x, RAD_MAX * 2.0f)); 4080 ImGui::EndTooltip(); 4081 } 4082 ImGui::SameLine(); 4083 HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically."); 4084 4085 ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. 4086 ImGui::PopItemWidth(); 4087 4088 ImGui::EndTabItem(); 4089 } 4090 4091 ImGui::EndTabBar(); 4092 } 4093 4094 ImGui::PopItemWidth(); 2322 4095 } 2323 4096 2324 // Demonstrate creating a fullscreen menu bar and populating it. 4097 //----------------------------------------------------------------------------- 4098 // [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar() 4099 //----------------------------------------------------------------------------- 4100 // - ShowExampleAppMainMenuBar() 4101 // - ShowExampleMenuFile() 4102 //----------------------------------------------------------------------------- 4103 4104 // Demonstrate creating a "main" fullscreen menu bar and populating it. 4105 // Note the difference between BeginMainMenuBar() and BeginMenuBar(): 4106 // - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!) 4107 // - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it. 2325 4108 static void ShowExampleAppMainMenuBar() 2326 4109 { 2327 if (ImGui::BeginMainMenuBar())2328 {2329 if (ImGui::BeginMenu("File"))2330 {2331 ShowExampleMenuFile();2332 ImGui::EndMenu();2333 }2334 if (ImGui::BeginMenu("Edit"))2335 {2336 if (ImGui::MenuItem("Undo", "CTRL+Z")) {}2337 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item2338 ImGui::Separator();2339 if (ImGui::MenuItem("Cut", "CTRL+X")) {}2340 if (ImGui::MenuItem("Copy", "CTRL+C")) {}2341 if (ImGui::MenuItem("Paste", "CTRL+V")) {}2342 ImGui::EndMenu();2343 }2344 ImGui::EndMainMenuBar();2345 }4110 if (ImGui::BeginMainMenuBar()) 4111 { 4112 if (ImGui::BeginMenu("File")) 4113 { 4114 ShowExampleMenuFile(); 4115 ImGui::EndMenu(); 4116 } 4117 if (ImGui::BeginMenu("Edit")) 4118 { 4119 if (ImGui::MenuItem("Undo", "CTRL+Z")) {} 4120 if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item 4121 ImGui::Separator(); 4122 if (ImGui::MenuItem("Cut", "CTRL+X")) {} 4123 if (ImGui::MenuItem("Copy", "CTRL+C")) {} 4124 if (ImGui::MenuItem("Paste", "CTRL+V")) {} 4125 ImGui::EndMenu(); 4126 } 4127 ImGui::EndMainMenuBar(); 4128 } 2346 4129 } 2347 4130 4131 // Note that shortcuts are currently provided for display only 4132 // (future version will add explicit flags to BeginMenu() to request processing shortcuts) 2348 4133 static void ShowExampleMenuFile() 2349 4134 { 2350 ImGui::MenuItem("(dummy menu)", NULL, false, false); 2351 if (ImGui::MenuItem("New")) {} 2352 if (ImGui::MenuItem("Open", "Ctrl+O")) {} 2353 if (ImGui::BeginMenu("Open Recent")) 2354 { 2355 ImGui::MenuItem("fish_hat.c"); 2356 ImGui::MenuItem("fish_hat.inl"); 2357 ImGui::MenuItem("fish_hat.h"); 2358 if (ImGui::BeginMenu("More..")) 2359 { 2360 ImGui::MenuItem("Hello"); 2361 ImGui::MenuItem("Sailor"); 2362 if (ImGui::BeginMenu("Recurse..")) 2363 { 2364 ShowExampleMenuFile(); 4135 ImGui::MenuItem("(demo menu)", NULL, false, false); 4136 if (ImGui::MenuItem("New")) {} 4137 if (ImGui::MenuItem("Open", "Ctrl+O")) {} 4138 if (ImGui::BeginMenu("Open Recent")) 4139 { 4140 ImGui::MenuItem("fish_hat.c"); 4141 ImGui::MenuItem("fish_hat.inl"); 4142 ImGui::MenuItem("fish_hat.h"); 4143 if (ImGui::BeginMenu("More..")) 4144 { 4145 ImGui::MenuItem("Hello"); 4146 ImGui::MenuItem("Sailor"); 4147 if (ImGui::BeginMenu("Recurse..")) 4148 { 4149 ShowExampleMenuFile(); 4150 ImGui::EndMenu(); 4151 } 2365 4152 ImGui::EndMenu(); 2366 } 2367 ImGui::EndMenu(); 2368 } 2369 ImGui::EndMenu(); 2370 } 2371 if (ImGui::MenuItem("Save", "Ctrl+S")) {} 2372 if (ImGui::MenuItem("Save As..")) {} 2373 ImGui::Separator(); 2374 if (ImGui::BeginMenu("Options")) 2375 { 2376 static bool enabled = true; 2377 ImGui::MenuItem("Enabled", "", &enabled); 2378 ImGui::BeginChild("child", ImVec2(0, 60), true); 2379 for (int i = 0; i < 10; i++) 2380 ImGui::Text("Scrolling Text %d", i); 2381 ImGui::EndChild(); 2382 static float f = 0.5f; 2383 static int n = 0; 2384 static bool b = true; 2385 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); 2386 ImGui::InputFloat("Input", &f, 0.1f); 2387 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); 2388 ImGui::Checkbox("Check", &b); 2389 ImGui::EndMenu(); 2390 } 2391 if (ImGui::BeginMenu("Colors")) 2392 { 2393 float sz = ImGui::GetTextLineHeight(); 2394 for (int i = 0; i < ImGuiCol_COUNT; i++) 2395 { 2396 const char* name = ImGui::GetStyleColorName((ImGuiCol)i); 2397 ImVec2 p = ImGui::GetCursorScreenPos(); 2398 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); 2399 ImGui::Dummy(ImVec2(sz, sz)); 2400 ImGui::SameLine(); 2401 ImGui::MenuItem(name); 2402 } 2403 ImGui::EndMenu(); 2404 } 2405 if (ImGui::BeginMenu("Disabled", false)) // Disabled 2406 { 2407 IM_ASSERT(0); 2408 } 2409 if (ImGui::MenuItem("Checked", NULL, true)) {} 2410 if (ImGui::MenuItem("Quit", "Alt+F4")) {} 4153 } 4154 ImGui::EndMenu(); 4155 } 4156 if (ImGui::MenuItem("Save", "Ctrl+S")) {} 4157 if (ImGui::MenuItem("Save As..")) {} 4158 4159 ImGui::Separator(); 4160 if (ImGui::BeginMenu("Options")) 4161 { 4162 static bool enabled = true; 4163 ImGui::MenuItem("Enabled", "", &enabled); 4164 ImGui::BeginChild("child", ImVec2(0, 60), true); 4165 for (int i = 0; i < 10; i++) 4166 ImGui::Text("Scrolling Text %d", i); 4167 ImGui::EndChild(); 4168 static float f = 0.5f; 4169 static int n = 0; 4170 ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); 4171 ImGui::InputFloat("Input", &f, 0.1f); 4172 ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0"); 4173 ImGui::EndMenu(); 4174 } 4175 4176 if (ImGui::BeginMenu("Colors")) 4177 { 4178 float sz = ImGui::GetTextLineHeight(); 4179 for (int i = 0; i < ImGuiCol_COUNT; i++) 4180 { 4181 const char* name = ImGui::GetStyleColorName((ImGuiCol)i); 4182 ImVec2 p = ImGui::GetCursorScreenPos(); 4183 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i)); 4184 ImGui::Dummy(ImVec2(sz, sz)); 4185 ImGui::SameLine(); 4186 ImGui::MenuItem(name); 4187 } 4188 ImGui::EndMenu(); 4189 } 4190 4191 // Here we demonstrate appending again to the "Options" menu (which we already created above) 4192 // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice. 4193 // In a real code-base using it would make senses to use this feature from very different code locations. 4194 if (ImGui::BeginMenu("Options")) // <-- Append! 4195 { 4196 static bool b = true; 4197 ImGui::Checkbox("SomeOption", &b); 4198 ImGui::EndMenu(); 4199 } 4200 4201 if (ImGui::BeginMenu("Disabled", false)) // Disabled 4202 { 4203 IM_ASSERT(0); 4204 } 4205 if (ImGui::MenuItem("Checked", NULL, true)) {} 4206 if (ImGui::MenuItem("Quit", "Alt+F4")) {} 2411 4207 } 2412 4208 2413 // Demonstrate creating a window which gets auto-resized according to its content. 2414 static void ShowExampleAppAutoResize(bool* p_open) 2415 { 2416 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 2417 { 2418 ImGui::End(); 2419 return; 2420 } 2421 2422 static int lines = 10; 2423 ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop."); 2424 ImGui::SliderInt("Number of lines", &lines, 1, 20); 2425 for (int i = 0; i < lines; i++) 2426 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally 2427 ImGui::End(); 2428 } 2429 2430 // Demonstrate creating a window with custom resize constraints. 2431 static void ShowExampleAppConstrainedResize(bool* p_open) 2432 { 2433 struct CustomConstraints // Helper functions to demonstrate programmatic constraints 2434 { 2435 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); } 2436 static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } 2437 }; 2438 2439 static bool auto_resize = false; 2440 static int type = 0; 2441 static int display_lines = 10; 2442 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only 2443 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only 2444 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 2445 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 2446 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 2447 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square 2448 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step 2449 2450 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; 2451 if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) 2452 { 2453 const char* desc[] = 2454 { 2455 "Resize vertical only", 2456 "Resize horizontal only", 2457 "Width > 100, Height > 100", 2458 "Width 400-500", 2459 "Height 400-500", 2460 "Custom: Always Square", 2461 "Custom: Fixed Steps (100)", 2462 }; 2463 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); 2464 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); 2465 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } 2466 ImGui::PushItemWidth(200); 2467 ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc)); 2468 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); 2469 ImGui::PopItemWidth(); 2470 ImGui::Checkbox("Auto-resize", &auto_resize); 2471 for (int i = 0; i < display_lines; i++) 2472 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); 2473 } 2474 ImGui::End(); 2475 } 2476 2477 // Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use. 2478 static void ShowExampleAppFixedOverlay(bool* p_open) 2479 { 2480 const float DISTANCE = 10.0f; 2481 static int corner = 0; 2482 ImVec2 window_pos = ImVec2((corner & 1) ? ImGui::GetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? ImGui::GetIO().DisplaySize.y - DISTANCE : DISTANCE); 2483 ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); 2484 if (corner != -1) 2485 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); 2486 ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background 2487 if (ImGui::Begin("Example: Fixed Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) 2488 { 2489 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); 2490 ImGui::Separator(); 2491 if (ImGui::IsMousePosValid()) 2492 ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y); 2493 else 2494 ImGui::Text("Mouse Position: <invalid>"); 2495 if (ImGui::BeginPopupContextWindow()) 2496 { 2497 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; 2498 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; 2499 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; 2500 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; 2501 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; 2502 if (p_open && ImGui::MenuItem("Close")) *p_open = false; 2503 ImGui::EndPopup(); 2504 } 2505 ImGui::End(); 2506 } 2507 } 2508 2509 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation. 2510 // This apply to regular items as well. Read FAQ section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." for details. 2511 static void ShowExampleAppWindowTitles(bool*) 2512 { 2513 // By default, Windows are uniquely identified by their title. 2514 // You can use the "##" and "###" markers to manipulate the display/ID. 2515 2516 // Using "##" to display same title but have unique identifier. 2517 ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); 2518 ImGui::Begin("Same title as another window##1"); 2519 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); 2520 ImGui::End(); 2521 2522 ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); 2523 ImGui::Begin("Same title as another window##2"); 2524 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); 2525 ImGui::End(); 2526 2527 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" 2528 char buf[128]; 2529 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); 2530 ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); 2531 ImGui::Begin(buf); 2532 ImGui::Text("This window has a changing title."); 2533 ImGui::End(); 2534 } 2535 2536 // Demonstrate using the low-level ImDrawList to draw custom shapes. 2537 static void ShowExampleAppCustomRendering(bool* p_open) 2538 { 2539 ImGui::SetNextWindowSize(ImVec2(350, 560), ImGuiCond_FirstUseEver); 2540 if (!ImGui::Begin("Example: Custom rendering", p_open)) 2541 { 2542 ImGui::End(); 2543 return; 2544 } 2545 2546 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc. 2547 // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4. 2548 // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types) 2549 // In this example we are not using the maths operators! 2550 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 2551 2552 // Primitives 2553 ImGui::Text("Primitives"); 2554 static float sz = 36.0f; 2555 static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); 2556 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); 2557 ImGui::ColorEdit3("Color", &col.x); 2558 { 2559 const ImVec2 p = ImGui::GetCursorScreenPos(); 2560 const ImU32 col32 = ImColor(col); 2561 float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f; 2562 for (int n = 0; n < 2; n++) 2563 { 2564 float thickness = (n == 0) ? 1.0f : 4.0f; 2565 draw_list->AddCircle(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col32, 20, thickness); x += sz + spacing; 2566 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 0.0f, ImDrawCornerFlags_All, thickness); x += sz + spacing; 2567 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_All, thickness); x += sz + spacing; 2568 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight, thickness); x += sz + spacing; 2569 draw_list->AddTriangle(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32, thickness); x += sz + spacing; 2570 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col32, thickness); x += sz + spacing; 2571 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, thickness); x += sz + spacing; 2572 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col32, thickness); x += spacing; 2573 draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz * 1.3f, y + sz * 0.3f), ImVec2(x + sz - sz * 1.3f, y + sz - sz * 0.3f), ImVec2(x + sz, y + sz), col32, thickness); 2574 x = p.x + 4; 2575 y += sz + spacing; 2576 } 2577 draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col32, 32); x += sz + spacing; 2578 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32); x += sz + spacing; 2579 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f); x += sz + spacing; 2580 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight); x += sz + spacing; 2581 draw_list->AddTriangleFilled(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32); x += sz + spacing; 2582 draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); 2583 ImGui::Dummy(ImVec2((sz + spacing) * 8, (sz + spacing) * 3)); 2584 } 2585 ImGui::Separator(); 2586 { 2587 static ImVector<ImVec2> points; 2588 static bool adding_line = false; 2589 ImGui::Text("Canvas example"); 2590 if (ImGui::Button("Clear")) points.clear(); 2591 if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } } 2592 ImGui::Text("Left-click and drag to add lines,\nRight-click to undo"); 2593 2594 // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered() 2595 // However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos(). 2596 // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max). 2597 ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! 2598 ImVec2 canvas_size = ImGui::GetContentRegionAvail(); // Resize canvas to what's available 2599 if (canvas_size.x < 50.0f) canvas_size.x = 50.0f; 2600 if (canvas_size.y < 50.0f) canvas_size.y = 50.0f; 2601 draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255)); 2602 draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255)); 2603 2604 bool adding_preview = false; 2605 ImGui::InvisibleButton("canvas", canvas_size); 2606 ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y); 2607 if (adding_line) 2608 { 2609 adding_preview = true; 2610 points.push_back(mouse_pos_in_canvas); 2611 if (!ImGui::IsMouseDown(0)) 2612 adding_line = adding_preview = false; 2613 } 2614 if (ImGui::IsItemHovered()) 2615 { 2616 if (!adding_line && ImGui::IsMouseClicked(0)) 2617 { 2618 points.push_back(mouse_pos_in_canvas); 2619 adding_line = true; 2620 } 2621 if (ImGui::IsMouseClicked(1) && !points.empty()) 2622 { 2623 adding_line = adding_preview = false; 2624 points.pop_back(); 2625 points.pop_back(); 2626 } 2627 } 2628 draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true); // clip lines within the canvas (if we resize it, etc.) 2629 for (int i = 0; i < points.Size - 1; i += 2) 2630 draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i + 1].x, canvas_pos.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); 2631 draw_list->PopClipRect(); 2632 if (adding_preview) 2633 points.pop_back(); 2634 } 2635 ImGui::End(); 2636 } 2637 2638 // Demonstrating creating a simple console window, with scrolling, filtering, completion and history. 2639 // For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions. 4209 //----------------------------------------------------------------------------- 4210 // [SECTION] Example App: Debug Console / ShowExampleAppConsole() 4211 //----------------------------------------------------------------------------- 4212 4213 // Demonstrate creating a simple console window, with scrolling, filtering, completion and history. 4214 // For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions. 2640 4215 struct ExampleAppConsole 2641 4216 { 2642 char InputBuf[256]; 2643 ImVector<char*> Items; 2644 bool ScrollToBottom; 2645 ImVector<char*> History; 2646 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. 2647 ImVector<const char*> Commands; 2648 2649 ExampleAppConsole() 2650 { 2651 ClearLog(); 2652 memset(InputBuf, 0, sizeof(InputBuf)); 2653 HistoryPos = -1; 2654 Commands.push_back("HELP"); 2655 Commands.push_back("HISTORY"); 2656 Commands.push_back("CLEAR"); 2657 Commands.push_back("CLASSIFY"); // "classify" is here to provide an example of "C"+[tab] completing to "CL" and displaying matches. 2658 AddLog("Welcome to ImGui!"); 2659 } 2660 ~ExampleAppConsole() 2661 { 2662 ClearLog(); 2663 for (int i = 0; i < History.Size; i++) 2664 free(History[i]); 2665 } 2666 2667 // Portable helpers 2668 static int Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; } 2669 static int Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; } 2670 static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); } 2671 2672 void ClearLog() 2673 { 2674 for (int i = 0; i < Items.Size; i++) 2675 free(Items[i]); 2676 Items.clear(); 2677 ScrollToBottom = true; 2678 } 2679 2680 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 2681 { 2682 // FIXME-OPT 2683 char buf[1024]; 2684 va_list args; 2685 va_start(args, fmt); 2686 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); 2687 buf[IM_ARRAYSIZE(buf) - 1] = 0; 2688 va_end(args); 2689 Items.push_back(Strdup(buf)); 2690 ScrollToBottom = true; 2691 } 2692 2693 void Draw(const char* title, bool* p_open) 2694 { 2695 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 2696 if (!ImGui::Begin(title, p_open)) 2697 { 2698 ImGui::End(); 2699 return; 2700 } 2701 2702 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar. 2703 // Here we create a context menu only available from the title bar. 2704 if (ImGui::BeginPopupContextItem()) 2705 { 2706 if (ImGui::MenuItem("Close")) 2707 *p_open = false; 2708 ImGui::EndPopup(); 2709 } 2710 2711 ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc."); 2712 ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); 2713 2714 // TODO: display items starting from the bottom 2715 2716 if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine(); 2717 if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine(); 2718 if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine(); 2719 bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine(); 2720 if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true; 2721 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } 2722 2723 ImGui::Separator(); 2724 2725 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); 2726 static ImGuiTextFilter filter; 2727 filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); 2728 ImGui::PopStyleVar(); 2729 ImGui::Separator(); 2730 2731 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text 2732 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText 2733 if (ImGui::BeginPopupContextWindow()) 2734 { 2735 if (ImGui::Selectable("Clear")) ClearLog(); 2736 ImGui::EndPopup(); 2737 } 2738 2739 // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); 2740 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items. 2741 // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements. 2742 // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with: 2743 // ImGuiListClipper clipper(Items.Size); 2744 // while (clipper.Step()) 2745 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 2746 // However take note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list. 2747 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter, 2748 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code! 2749 // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list. 2750 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing 2751 if (copy_to_clipboard) 2752 ImGui::LogToClipboard(); 2753 ImVec4 col_default_text = ImGui::GetStyleColorVec4(ImGuiCol_Text); 2754 for (int i = 0; i < Items.Size; i++) 2755 { 2756 const char* item = Items[i]; 2757 if (!filter.PassFilter(item)) 2758 continue; 2759 ImVec4 col = col_default_text; 2760 if (strstr(item, "[error]")) col = ImColor(1.0f, 0.4f, 0.4f, 1.0f); 2761 else if (strncmp(item, "# ", 2) == 0) col = ImColor(1.0f, 0.78f, 0.58f, 1.0f); 2762 ImGui::PushStyleColor(ImGuiCol_Text, col); 2763 ImGui::TextUnformatted(item); 2764 ImGui::PopStyleColor(); 2765 } 2766 if (copy_to_clipboard) 2767 ImGui::LogFinish(); 2768 if (ScrollToBottom) 2769 ImGui::SetScrollHere(); 2770 ScrollToBottom = false; 2771 ImGui::PopStyleVar(); 2772 ImGui::EndChild(); 2773 ImGui::Separator(); 2774 2775 // Command-line 2776 bool reclaim_focus = false; 2777 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this)) 2778 { 2779 char* input_end = InputBuf + strlen(InputBuf); 2780 while (input_end > InputBuf && input_end[-1] == ' ') { input_end--; } *input_end = 0; 2781 if (InputBuf[0]) 2782 ExecCommand(InputBuf); 2783 strcpy(InputBuf, ""); 2784 reclaim_focus = true; 2785 } 2786 2787 // Demonstrate keeping focus on the input box 2788 ImGui::SetItemDefaultFocus(); 2789 if (reclaim_focus) 2790 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget 2791 2792 ImGui::End(); 2793 } 2794 2795 void ExecCommand(const char* command_line) 2796 { 2797 AddLog("# %s\n", command_line); 2798 2799 // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal. 2800 HistoryPos = -1; 2801 for (int i = History.Size - 1; i >= 0; i--) 2802 if (Stricmp(History[i], command_line) == 0) 2803 { 4217 char InputBuf[256]; 4218 ImVector<char*> Items; 4219 ImVector<const char*> Commands; 4220 ImVector<char*> History; 4221 int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. 4222 ImGuiTextFilter Filter; 4223 bool AutoScroll; 4224 bool ScrollToBottom; 4225 4226 ExampleAppConsole() 4227 { 4228 ClearLog(); 4229 memset(InputBuf, 0, sizeof(InputBuf)); 4230 HistoryPos = -1; 4231 4232 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches. 4233 Commands.push_back("HELP"); 4234 Commands.push_back("HISTORY"); 4235 Commands.push_back("CLEAR"); 4236 Commands.push_back("CLASSIFY"); 4237 AutoScroll = true; 4238 ScrollToBottom = false; 4239 AddLog("Welcome to Dear ImGui!"); 4240 } 4241 ~ExampleAppConsole() 4242 { 4243 ClearLog(); 4244 for (int i = 0; i < History.Size; i++) 2804 4245 free(History[i]); 2805 History.erase(History.begin() + i); 2806 break; 2807 } 2808 History.push_back(Strdup(command_line)); 2809 2810 // Process command 2811 if (Stricmp(command_line, "CLEAR") == 0) 2812 { 2813 ClearLog(); 2814 } 2815 else if (Stricmp(command_line, "HELP") == 0) 2816 { 2817 AddLog("Commands:"); 2818 for (int i = 0; i < Commands.Size; i++) 2819 AddLog("- %s", Commands[i]); 2820 } 2821 else if (Stricmp(command_line, "HISTORY") == 0) 2822 { 2823 int first = History.Size - 10; 2824 for (int i = first > 0 ? first : 0; i < History.Size; i++) 2825 AddLog("%3d: %s\n", i, History[i]); 2826 } 2827 else 2828 { 2829 AddLog("Unknown command: '%s'\n", command_line); 2830 } 2831 } 2832 2833 static int TextEditCallbackStub(ImGuiTextEditCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks 2834 { 2835 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; 2836 return console->TextEditCallback(data); 2837 } 2838 2839 int TextEditCallback(ImGuiTextEditCallbackData* data) 2840 { 2841 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); 2842 switch (data->EventFlag) 2843 { 2844 case ImGuiInputTextFlags_CallbackCompletion: 2845 { 2846 // Example of TEXT COMPLETION 2847 2848 // Locate beginning of current word 2849 const char* word_end = data->Buf + data->CursorPos; 2850 const char* word_start = word_end; 2851 while (word_start > data->Buf) 2852 { 2853 const char c = word_start[-1]; 2854 if (c == ' ' || c == '\t' || c == ',' || c == ';') 2855 break; 2856 word_start--; 2857 } 2858 2859 // Build a list of candidates 2860 ImVector<const char*> candidates; 2861 for (int i = 0; i < Commands.Size; i++) 2862 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) 2863 candidates.push_back(Commands[i]); 2864 2865 if (candidates.Size == 0) 2866 { 2867 // No match 2868 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); 2869 } 2870 else if (candidates.Size == 1) 2871 { 2872 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing 2873 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 2874 data->InsertChars(data->CursorPos, candidates[0]); 2875 data->InsertChars(data->CursorPos, " "); 2876 } 2877 else 2878 { 2879 // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY" 2880 int match_len = (int)(word_end - word_start); 2881 for (;;) 2882 { 2883 int c = 0; 2884 bool all_candidates_matches = true; 2885 for (int i = 0; i < candidates.Size && all_candidates_matches; i++) 2886 if (i == 0) 2887 c = toupper(candidates[i][match_len]); 2888 else if (c == 0 || c != toupper(candidates[i][match_len])) 2889 all_candidates_matches = false; 2890 if (!all_candidates_matches) 2891 break; 2892 match_len++; 2893 } 2894 2895 if (match_len > 0) 2896 { 2897 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 2898 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); 2899 } 2900 2901 // List matches 2902 AddLog("Possible matches:\n"); 2903 for (int i = 0; i < candidates.Size; i++) 2904 AddLog("- %s\n", candidates[i]); 2905 } 2906 2907 break; 2908 } 2909 case ImGuiInputTextFlags_CallbackHistory: 2910 { 2911 // Example of HISTORY 2912 const int prev_history_pos = HistoryPos; 2913 if (data->EventKey == ImGuiKey_UpArrow) 2914 { 2915 if (HistoryPos == -1) 2916 HistoryPos = History.Size - 1; 2917 else if (HistoryPos > 0) 2918 HistoryPos--; 2919 } 2920 else if (data->EventKey == ImGuiKey_DownArrow) 2921 { 2922 if (HistoryPos != -1) 2923 if (++HistoryPos >= History.Size) 2924 HistoryPos = -1; 2925 } 2926 2927 // A better implementation would preserve the data on the current input line along with cursor position. 2928 if (prev_history_pos != HistoryPos) 2929 { 2930 data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = (int)snprintf(data->Buf, (size_t)data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : ""); 2931 data->BufDirty = true; 2932 } 2933 } 2934 } 2935 return 0; 2936 } 4246 } 4247 4248 // Portable helpers 4249 static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; } 4250 static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; } 4251 static char* Strdup(const char* s) { size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); } 4252 static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } 4253 4254 void ClearLog() 4255 { 4256 for (int i = 0; i < Items.Size; i++) 4257 free(Items[i]); 4258 Items.clear(); 4259 } 4260 4261 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 4262 { 4263 // FIXME-OPT 4264 char buf[1024]; 4265 va_list args; 4266 va_start(args, fmt); 4267 vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args); 4268 buf[IM_ARRAYSIZE(buf)-1] = 0; 4269 va_end(args); 4270 Items.push_back(Strdup(buf)); 4271 } 4272 4273 void Draw(const char* title, bool* p_open) 4274 { 4275 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 4276 if (!ImGui::Begin(title, p_open)) 4277 { 4278 ImGui::End(); 4279 return; 4280 } 4281 4282 // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. 4283 // So e.g. IsItemHovered() will return true when hovering the title bar. 4284 // Here we create a context menu only available from the title bar. 4285 if (ImGui::BeginPopupContextItem()) 4286 { 4287 if (ImGui::MenuItem("Close Console")) 4288 *p_open = false; 4289 ImGui::EndPopup(); 4290 } 4291 4292 ImGui::TextWrapped( 4293 "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate " 4294 "implementation may want to store entries along with extra data such as timestamp, emitter, etc."); 4295 ImGui::TextWrapped("Enter 'HELP' for help."); 4296 4297 // TODO: display items starting from the bottom 4298 4299 if (ImGui::SmallButton("Add Debug Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } 4300 ImGui::SameLine(); 4301 if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); } 4302 ImGui::SameLine(); 4303 if (ImGui::SmallButton("Clear")) { ClearLog(); } 4304 ImGui::SameLine(); 4305 bool copy_to_clipboard = ImGui::SmallButton("Copy"); 4306 //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); } 4307 4308 ImGui::Separator(); 4309 4310 // Options menu 4311 if (ImGui::BeginPopup("Options")) 4312 { 4313 ImGui::Checkbox("Auto-scroll", &AutoScroll); 4314 ImGui::EndPopup(); 4315 } 4316 4317 // Options, Filter 4318 if (ImGui::Button("Options")) 4319 ImGui::OpenPopup("Options"); 4320 ImGui::SameLine(); 4321 Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180); 4322 ImGui::Separator(); 4323 4324 // Reserve enough left-over height for 1 separator + 1 input text 4325 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); 4326 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); 4327 if (ImGui::BeginPopupContextWindow()) 4328 { 4329 if (ImGui::Selectable("Clear")) ClearLog(); 4330 ImGui::EndPopup(); 4331 } 4332 4333 // Display every line as a separate entry so we can change their color or add custom widgets. 4334 // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); 4335 // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping 4336 // to only process visible items. The clipper will automatically measure the height of your first item and then 4337 // "seek" to display only items in the visible area. 4338 // To use the clipper we can replace your standard loop: 4339 // for (int i = 0; i < Items.Size; i++) 4340 // With: 4341 // ImGuiListClipper clipper; 4342 // clipper.Begin(Items.Size); 4343 // while (clipper.Step()) 4344 // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 4345 // - That your items are evenly spaced (same height) 4346 // - That you have cheap random access to your elements (you can access them given their index, 4347 // without processing all the ones before) 4348 // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. 4349 // We would need random-access on the post-filtered list. 4350 // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices 4351 // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, 4352 // and appending newly elements as they are inserted. This is left as a task to the user until we can manage 4353 // to improve this example code! 4354 // If your items are of variable height: 4355 // - Split them into same height items would be simpler and facilitate random-seeking into your list. 4356 // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. 4357 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing 4358 if (copy_to_clipboard) 4359 ImGui::LogToClipboard(); 4360 for (int i = 0; i < Items.Size; i++) 4361 { 4362 const char* item = Items[i]; 4363 if (!Filter.PassFilter(item)) 4364 continue; 4365 4366 // Normally you would store more information in your item than just a string. 4367 // (e.g. make Items[] an array of structure, store color/type etc.) 4368 ImVec4 color; 4369 bool has_color = false; 4370 if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } 4371 else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } 4372 if (has_color) 4373 ImGui::PushStyleColor(ImGuiCol_Text, color); 4374 ImGui::TextUnformatted(item); 4375 if (has_color) 4376 ImGui::PopStyleColor(); 4377 } 4378 if (copy_to_clipboard) 4379 ImGui::LogFinish(); 4380 4381 if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) 4382 ImGui::SetScrollHereY(1.0f); 4383 ScrollToBottom = false; 4384 4385 ImGui::PopStyleVar(); 4386 ImGui::EndChild(); 4387 ImGui::Separator(); 4388 4389 // Command-line 4390 bool reclaim_focus = false; 4391 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; 4392 if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) 4393 { 4394 char* s = InputBuf; 4395 Strtrim(s); 4396 if (s[0]) 4397 ExecCommand(s); 4398 strcpy(s, ""); 4399 reclaim_focus = true; 4400 } 4401 4402 // Auto-focus on window apparition 4403 ImGui::SetItemDefaultFocus(); 4404 if (reclaim_focus) 4405 ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget 4406 4407 ImGui::End(); 4408 } 4409 4410 void ExecCommand(const char* command_line) 4411 { 4412 AddLog("# %s\n", command_line); 4413 4414 // Insert into history. First find match and delete it so it can be pushed to the back. 4415 // This isn't trying to be smart or optimal. 4416 HistoryPos = -1; 4417 for (int i = History.Size - 1; i >= 0; i--) 4418 if (Stricmp(History[i], command_line) == 0) 4419 { 4420 free(History[i]); 4421 History.erase(History.begin() + i); 4422 break; 4423 } 4424 History.push_back(Strdup(command_line)); 4425 4426 // Process command 4427 if (Stricmp(command_line, "CLEAR") == 0) 4428 { 4429 ClearLog(); 4430 } 4431 else if (Stricmp(command_line, "HELP") == 0) 4432 { 4433 AddLog("Commands:"); 4434 for (int i = 0; i < Commands.Size; i++) 4435 AddLog("- %s", Commands[i]); 4436 } 4437 else if (Stricmp(command_line, "HISTORY") == 0) 4438 { 4439 int first = History.Size - 10; 4440 for (int i = first > 0 ? first : 0; i < History.Size; i++) 4441 AddLog("%3d: %s\n", i, History[i]); 4442 } 4443 else 4444 { 4445 AddLog("Unknown command: '%s'\n", command_line); 4446 } 4447 4448 // On command input, we scroll to bottom even if AutoScroll==false 4449 ScrollToBottom = true; 4450 } 4451 4452 // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks 4453 static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) 4454 { 4455 ExampleAppConsole* console = (ExampleAppConsole*)data->UserData; 4456 return console->TextEditCallback(data); 4457 } 4458 4459 int TextEditCallback(ImGuiInputTextCallbackData* data) 4460 { 4461 //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd); 4462 switch (data->EventFlag) 4463 { 4464 case ImGuiInputTextFlags_CallbackCompletion: 4465 { 4466 // Example of TEXT COMPLETION 4467 4468 // Locate beginning of current word 4469 const char* word_end = data->Buf + data->CursorPos; 4470 const char* word_start = word_end; 4471 while (word_start > data->Buf) 4472 { 4473 const char c = word_start[-1]; 4474 if (c == ' ' || c == '\t' || c == ',' || c == ';') 4475 break; 4476 word_start--; 4477 } 4478 4479 // Build a list of candidates 4480 ImVector<const char*> candidates; 4481 for (int i = 0; i < Commands.Size; i++) 4482 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0) 4483 candidates.push_back(Commands[i]); 4484 4485 if (candidates.Size == 0) 4486 { 4487 // No match 4488 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start); 4489 } 4490 else if (candidates.Size == 1) 4491 { 4492 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing. 4493 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 4494 data->InsertChars(data->CursorPos, candidates[0]); 4495 data->InsertChars(data->CursorPos, " "); 4496 } 4497 else 4498 { 4499 // Multiple matches. Complete as much as we can.. 4500 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. 4501 int match_len = (int)(word_end - word_start); 4502 for (;;) 4503 { 4504 int c = 0; 4505 bool all_candidates_matches = true; 4506 for (int i = 0; i < candidates.Size && all_candidates_matches; i++) 4507 if (i == 0) 4508 c = toupper(candidates[i][match_len]); 4509 else if (c == 0 || c != toupper(candidates[i][match_len])) 4510 all_candidates_matches = false; 4511 if (!all_candidates_matches) 4512 break; 4513 match_len++; 4514 } 4515 4516 if (match_len > 0) 4517 { 4518 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start)); 4519 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len); 4520 } 4521 4522 // List matches 4523 AddLog("Possible matches:\n"); 4524 for (int i = 0; i < candidates.Size; i++) 4525 AddLog("- %s\n", candidates[i]); 4526 } 4527 4528 break; 4529 } 4530 case ImGuiInputTextFlags_CallbackHistory: 4531 { 4532 // Example of HISTORY 4533 const int prev_history_pos = HistoryPos; 4534 if (data->EventKey == ImGuiKey_UpArrow) 4535 { 4536 if (HistoryPos == -1) 4537 HistoryPos = History.Size - 1; 4538 else if (HistoryPos > 0) 4539 HistoryPos--; 4540 } 4541 else if (data->EventKey == ImGuiKey_DownArrow) 4542 { 4543 if (HistoryPos != -1) 4544 if (++HistoryPos >= History.Size) 4545 HistoryPos = -1; 4546 } 4547 4548 // A better implementation would preserve the data on the current input line along with cursor position. 4549 if (prev_history_pos != HistoryPos) 4550 { 4551 const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : ""; 4552 data->DeleteChars(0, data->BufTextLen); 4553 data->InsertChars(0, history_str); 4554 } 4555 } 4556 } 4557 return 0; 4558 } 2937 4559 }; 2938 4560 2939 4561 static void ShowExampleAppConsole(bool* p_open) 2940 4562 { 2941 static ExampleAppConsole console;2942 console.Draw("Example: Console", p_open);4563 static ExampleAppConsole console; 4564 console.Draw("Example: Console", p_open); 2943 4565 } 4566 4567 //----------------------------------------------------------------------------- 4568 // [SECTION] Example App: Debug Log / ShowExampleAppLog() 4569 //----------------------------------------------------------------------------- 2944 4570 2945 4571 // Usage: … … 2949 4575 struct ExampleAppLog 2950 4576 { 2951 ImGuiTextBuffer Buf; 2952 ImGuiTextFilter Filter; 2953 ImVector<int> LineOffsets; // Index to lines offset 2954 bool ScrollToBottom; 2955 2956 void Clear() { Buf.clear(); LineOffsets.clear(); } 2957 2958 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 2959 { 2960 int old_size = Buf.size(); 2961 va_list args; 2962 va_start(args, fmt); 2963 Buf.appendfv(fmt, args); 2964 va_end(args); 2965 for (int new_size = Buf.size(); old_size < new_size; old_size++) 2966 if (Buf[old_size] == '\n') 2967 LineOffsets.push_back(old_size); 2968 ScrollToBottom = true; 2969 } 2970 2971 void Draw(const char* title, bool* p_open = NULL) 2972 { 2973 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); 2974 ImGui::Begin(title, p_open); 2975 if (ImGui::Button("Clear")) Clear(); 2976 ImGui::SameLine(); 2977 bool copy = ImGui::Button("Copy"); 2978 ImGui::SameLine(); 2979 Filter.Draw("Filter", -100.0f); 2980 ImGui::Separator(); 2981 ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); 2982 if (copy) ImGui::LogToClipboard(); 2983 2984 if (Filter.IsActive()) 2985 { 2986 const char* buf_begin = Buf.begin(); 2987 const char* line = buf_begin; 2988 for (int line_no = 0; line != NULL; line_no++) 2989 { 2990 const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL; 2991 if (Filter.PassFilter(line, line_end)) 2992 ImGui::TextUnformatted(line, line_end); 2993 line = line_end && line_end[1] ? line_end + 1 : NULL; 2994 } 2995 } 2996 else 2997 { 2998 ImGui::TextUnformatted(Buf.begin()); 2999 } 3000 3001 if (ScrollToBottom) 3002 ImGui::SetScrollHere(1.0f); 3003 ScrollToBottom = false; 3004 ImGui::EndChild(); 3005 ImGui::End(); 3006 } 4577 ImGuiTextBuffer Buf; 4578 ImGuiTextFilter Filter; 4579 ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. 4580 bool AutoScroll; // Keep scrolling if already at the bottom. 4581 4582 ExampleAppLog() 4583 { 4584 AutoScroll = true; 4585 Clear(); 4586 } 4587 4588 void Clear() 4589 { 4590 Buf.clear(); 4591 LineOffsets.clear(); 4592 LineOffsets.push_back(0); 4593 } 4594 4595 void AddLog(const char* fmt, ...) IM_FMTARGS(2) 4596 { 4597 int old_size = Buf.size(); 4598 va_list args; 4599 va_start(args, fmt); 4600 Buf.appendfv(fmt, args); 4601 va_end(args); 4602 for (int new_size = Buf.size(); old_size < new_size; old_size++) 4603 if (Buf[old_size] == '\n') 4604 LineOffsets.push_back(old_size + 1); 4605 } 4606 4607 void Draw(const char* title, bool* p_open = NULL) 4608 { 4609 if (!ImGui::Begin(title, p_open)) 4610 { 4611 ImGui::End(); 4612 return; 4613 } 4614 4615 // Options menu 4616 if (ImGui::BeginPopup("Options")) 4617 { 4618 ImGui::Checkbox("Auto-scroll", &AutoScroll); 4619 ImGui::EndPopup(); 4620 } 4621 4622 // Main window 4623 if (ImGui::Button("Options")) 4624 ImGui::OpenPopup("Options"); 4625 ImGui::SameLine(); 4626 bool clear = ImGui::Button("Clear"); 4627 ImGui::SameLine(); 4628 bool copy = ImGui::Button("Copy"); 4629 ImGui::SameLine(); 4630 Filter.Draw("Filter", -100.0f); 4631 4632 ImGui::Separator(); 4633 ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); 4634 4635 if (clear) 4636 Clear(); 4637 if (copy) 4638 ImGui::LogToClipboard(); 4639 4640 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 4641 const char* buf = Buf.begin(); 4642 const char* buf_end = Buf.end(); 4643 if (Filter.IsActive()) 4644 { 4645 // In this example we don't use the clipper when Filter is enabled. 4646 // This is because we don't have a random access on the result on our filter. 4647 // A real application processing logs with ten of thousands of entries may want to store the result of 4648 // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). 4649 for (int line_no = 0; line_no < LineOffsets.Size; line_no++) 4650 { 4651 const char* line_start = buf + LineOffsets[line_no]; 4652 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 4653 if (Filter.PassFilter(line_start, line_end)) 4654 ImGui::TextUnformatted(line_start, line_end); 4655 } 4656 } 4657 else 4658 { 4659 // The simplest and easy way to display the entire buffer: 4660 // ImGui::TextUnformatted(buf_begin, buf_end); 4661 // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward 4662 // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are 4663 // within the visible area. 4664 // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them 4665 // on your side is recommended. Using ImGuiListClipper requires 4666 // - A) random access into your data 4667 // - B) items all being the same height, 4668 // both of which we can handle since we an array pointing to the beginning of each line of text. 4669 // When using the filter (in the block of code above) we don't have random access into the data to display 4670 // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make 4671 // it possible (and would be recommended if you want to search through tens of thousands of entries). 4672 ImGuiListClipper clipper; 4673 clipper.Begin(LineOffsets.Size); 4674 while (clipper.Step()) 4675 { 4676 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) 4677 { 4678 const char* line_start = buf + LineOffsets[line_no]; 4679 const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; 4680 ImGui::TextUnformatted(line_start, line_end); 4681 } 4682 } 4683 clipper.End(); 4684 } 4685 ImGui::PopStyleVar(); 4686 4687 if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) 4688 ImGui::SetScrollHereY(1.0f); 4689 4690 ImGui::EndChild(); 4691 ImGui::End(); 4692 } 3007 4693 }; 3008 4694 … … 3010 4696 static void ShowExampleAppLog(bool* p_open) 3011 4697 { 3012 static ExampleAppLog log; 3013 3014 // Demo: add random items (unless Ctrl is held) 3015 static float last_time = -1.0f; 3016 float time = ImGui::GetTime(); 3017 if (time - last_time >= 0.20f && !ImGui::GetIO().KeyCtrl) 3018 { 3019 const char* random_words[] = { "system", "info", "warning", "error", "fatal", "notice", "log" }; 3020 log.AddLog("[%s] Hello, time is %.1f, frame count is %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, ImGui::GetFrameCount()); 3021 last_time = time; 3022 } 3023 3024 log.Draw("Example: Log", p_open); 4698 static ExampleAppLog log; 4699 4700 // For the demo: add a debug button _BEFORE_ the normal log window contents 4701 // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. 4702 // Most of the contents of the window will be added by the log.Draw() call. 4703 ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); 4704 ImGui::Begin("Example: Log", p_open); 4705 if (ImGui::SmallButton("[Debug] Add 5 entries")) 4706 { 4707 static int counter = 0; 4708 const char* categories[3] = { "info", "warn", "error" }; 4709 const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; 4710 for (int n = 0; n < 5; n++) 4711 { 4712 const char* category = categories[counter % IM_ARRAYSIZE(categories)]; 4713 const char* word = words[counter % IM_ARRAYSIZE(words)]; 4714 log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", 4715 ImGui::GetFrameCount(), category, ImGui::GetTime(), word); 4716 counter++; 4717 } 4718 } 4719 ImGui::End(); 4720 4721 // Actually call in the regular Log helper (which will Begin() into the same window as we just did) 4722 log.Draw("Example: Log", p_open); 3025 4723 } 4724 4725 //----------------------------------------------------------------------------- 4726 // [SECTION] Example App: Simple Layout / ShowExampleAppLayout() 4727 //----------------------------------------------------------------------------- 3026 4728 3027 4729 // Demonstrate create a window with multiple child windows. 3028 4730 static void ShowExampleAppLayout(bool* p_open) 3029 4731 { 3030 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); 3031 if (ImGui::Begin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar)) 3032 { 3033 if (ImGui::BeginMenuBar()) 3034 { 3035 if (ImGui::BeginMenu("File")) 3036 { 3037 if (ImGui::MenuItem("Close")) *p_open = false; 3038 ImGui::EndMenu(); 3039 } 3040 ImGui::EndMenuBar(); 3041 } 3042 3043 // left 3044 static int selected = 0; 3045 ImGui::BeginChild("left pane", ImVec2(150, 0), true); 3046 for (int i = 0; i < 100; i++) 3047 { 3048 char label[128]; 3049 sprintf(label, "MyObject %d", i); 3050 if (ImGui::Selectable(label, selected == i)) 3051 selected = i; 3052 } 3053 ImGui::EndChild(); 3054 ImGui::SameLine(); 3055 3056 // right 3057 ImGui::BeginGroup(); 3058 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us 3059 ImGui::Text("MyObject: %d", selected); 3060 ImGui::Separator(); 3061 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); 3062 ImGui::EndChild(); 3063 if (ImGui::Button("Revert")) {} 3064 ImGui::SameLine(); 3065 if (ImGui::Button("Save")) {} 3066 ImGui::EndGroup(); 3067 } 3068 ImGui::End(); 4732 ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); 4733 if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) 4734 { 4735 if (ImGui::BeginMenuBar()) 4736 { 4737 if (ImGui::BeginMenu("File")) 4738 { 4739 if (ImGui::MenuItem("Close")) *p_open = false; 4740 ImGui::EndMenu(); 4741 } 4742 ImGui::EndMenuBar(); 4743 } 4744 4745 // Left 4746 static int selected = 0; 4747 { 4748 ImGui::BeginChild("left pane", ImVec2(150, 0), true); 4749 for (int i = 0; i < 100; i++) 4750 { 4751 char label[128]; 4752 sprintf(label, "MyObject %d", i); 4753 if (ImGui::Selectable(label, selected == i)) 4754 selected = i; 4755 } 4756 ImGui::EndChild(); 4757 } 4758 ImGui::SameLine(); 4759 4760 // Right 4761 { 4762 ImGui::BeginGroup(); 4763 ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us 4764 ImGui::Text("MyObject: %d", selected); 4765 ImGui::Separator(); 4766 if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) 4767 { 4768 if (ImGui::BeginTabItem("Description")) 4769 { 4770 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "); 4771 ImGui::EndTabItem(); 4772 } 4773 if (ImGui::BeginTabItem("Details")) 4774 { 4775 ImGui::Text("ID: 0123456789"); 4776 ImGui::EndTabItem(); 4777 } 4778 ImGui::EndTabBar(); 4779 } 4780 ImGui::EndChild(); 4781 if (ImGui::Button("Revert")) {} 4782 ImGui::SameLine(); 4783 if (ImGui::Button("Save")) {} 4784 ImGui::EndGroup(); 4785 } 4786 } 4787 ImGui::End(); 4788 } 4789 4790 //----------------------------------------------------------------------------- 4791 // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() 4792 //----------------------------------------------------------------------------- 4793 4794 static void ShowPlaceholderObject(const char* prefix, int uid) 4795 { 4796 // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. 4797 ImGui::PushID(uid); 4798 4799 // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high. 4800 ImGui::AlignTextToFramePadding(); 4801 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); 4802 ImGui::NextColumn(); 4803 ImGui::AlignTextToFramePadding(); 4804 ImGui::Text("my sailor is rich"); 4805 ImGui::NextColumn(); 4806 if (node_open) 4807 { 4808 static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f }; 4809 for (int i = 0; i < 8; i++) 4810 { 4811 ImGui::PushID(i); // Use field index as identifier. 4812 if (i < 2) 4813 { 4814 ShowPlaceholderObject("Child", 424242); 4815 } 4816 else 4817 { 4818 // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well) 4819 ImGui::AlignTextToFramePadding(); 4820 ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet; 4821 ImGui::TreeNodeEx("Field", flags, "Field_%d", i); 4822 ImGui::NextColumn(); 4823 ImGui::SetNextItemWidth(-1); 4824 if (i >= 5) 4825 ImGui::InputFloat("##value", &placeholder_members[i], 1.0f); 4826 else 4827 ImGui::DragFloat("##value", &placeholder_members[i], 0.01f); 4828 ImGui::NextColumn(); 4829 } 4830 ImGui::PopID(); 4831 } 4832 ImGui::TreePop(); 4833 } 4834 ImGui::PopID(); 3069 4835 } 3070 4836 … … 3072 4838 static void ShowExampleAppPropertyEditor(bool* p_open) 3073 4839 { 3074 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); 3075 if (!ImGui::Begin("Example: Property editor", p_open)) 3076 { 3077 ImGui::End(); 3078 return; 3079 } 3080 3081 ShowHelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API."); 3082 3083 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); 3084 ImGui::Columns(2); 3085 ImGui::Separator(); 3086 3087 struct funcs 3088 { 3089 static void ShowDummyObject(const char* prefix, int uid) 3090 { 3091 ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. 3092 ImGui::AlignTextToFramePadding(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. 3093 bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid); 3094 ImGui::NextColumn(); 3095 ImGui::AlignTextToFramePadding(); 3096 ImGui::Text("my sailor is rich"); 3097 ImGui::NextColumn(); 3098 if (node_open) 3099 { 3100 static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; 3101 for (int i = 0; i < 8; i++) 3102 { 3103 ImGui::PushID(i); // Use field index as identifier. 3104 if (i < 2) 3105 { 3106 ShowDummyObject("Child", 424242); 3107 } 3108 else 3109 { 3110 ImGui::AlignTextToFramePadding(); 3111 // Here we use a Selectable (instead of Text) to highlight on hover 3112 //ImGui::Text("Field_%d", i); 3113 char label[32]; 3114 sprintf(label, "Field_%d", i); 3115 ImGui::Bullet(); 3116 ImGui::Selectable(label); 3117 ImGui::NextColumn(); 3118 ImGui::PushItemWidth(-1); 3119 if (i >= 5) 3120 ImGui::InputFloat("##value", &dummy_members[i], 1.0f); 3121 else 3122 ImGui::DragFloat("##value", &dummy_members[i], 0.01f); 3123 ImGui::PopItemWidth(); 3124 ImGui::NextColumn(); 3125 } 3126 ImGui::PopID(); 3127 } 3128 ImGui::TreePop(); 3129 } 3130 ImGui::PopID(); 3131 } 3132 }; 3133 3134 // Iterate dummy objects with dummy members (all the same data) 3135 for (int obj_i = 0; obj_i < 3; obj_i++) 3136 funcs::ShowDummyObject("Object", obj_i); 3137 3138 ImGui::Columns(1); 3139 ImGui::Separator(); 3140 ImGui::PopStyleVar(); 3141 ImGui::End(); 4840 ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); 4841 if (!ImGui::Begin("Example: Property editor", p_open)) 4842 { 4843 ImGui::End(); 4844 return; 4845 } 4846 4847 HelpMarker( 4848 "This example shows how you may implement a property editor using two columns.\n" 4849 "All objects/fields data are dummies here.\n" 4850 "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n" 4851 "your cursor horizontally instead of using the Columns() API."); 4852 4853 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); 4854 ImGui::Columns(2); 4855 ImGui::Separator(); 4856 4857 // Iterate placeholder objects (all the same data) 4858 for (int obj_i = 0; obj_i < 3; obj_i++) 4859 ShowPlaceholderObject("Object", obj_i); 4860 4861 ImGui::Columns(1); 4862 ImGui::Separator(); 4863 ImGui::PopStyleVar(); 4864 ImGui::End(); 3142 4865 } 4866 4867 //----------------------------------------------------------------------------- 4868 // [SECTION] Example App: Long Text / ShowExampleAppLongText() 4869 //----------------------------------------------------------------------------- 3143 4870 3144 4871 // Demonstrate/test rendering huge amount of text, and the incidence of clipping. 3145 4872 static void ShowExampleAppLongText(bool* p_open) 3146 4873 { 3147 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 3148 if (!ImGui::Begin("Example: Long text display", p_open)) 3149 { 3150 ImGui::End(); 3151 return; 3152 } 3153 3154 static int test_type = 0; 3155 static ImGuiTextBuffer log; 3156 static int lines = 0; 3157 ImGui::Text("Printing unusually long amount of text."); 3158 ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0"); 3159 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); 3160 if (ImGui::Button("Clear")) { log.clear(); lines = 0; } 3161 ImGui::SameLine(); 3162 if (ImGui::Button("Add 1000 lines")) 3163 { 3164 for (int i = 0; i < 1000; i++) 3165 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); 3166 lines += 1000; 3167 } 3168 ImGui::BeginChild("Log"); 3169 switch (test_type) 3170 { 3171 case 0: 3172 // Single call to TextUnformatted() with a big buffer 3173 ImGui::TextUnformatted(log.begin(), log.end()); 3174 break; 3175 case 1: 3176 { 3177 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. 3178 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 3179 ImGuiListClipper clipper(lines); 3180 while (clipper.Step()) 3181 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 4874 ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); 4875 if (!ImGui::Begin("Example: Long text display", p_open)) 4876 { 4877 ImGui::End(); 4878 return; 4879 } 4880 4881 static int test_type = 0; 4882 static ImGuiTextBuffer log; 4883 static int lines = 0; 4884 ImGui::Text("Printing unusually long amount of text."); 4885 ImGui::Combo("Test type", &test_type, 4886 "Single call to TextUnformatted()\0" 4887 "Multiple calls to Text(), clipped\0" 4888 "Multiple calls to Text(), not clipped (slow)\0"); 4889 ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); 4890 if (ImGui::Button("Clear")) { log.clear(); lines = 0; } 4891 ImGui::SameLine(); 4892 if (ImGui::Button("Add 1000 lines")) 4893 { 4894 for (int i = 0; i < 1000; i++) 4895 log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); 4896 lines += 1000; 4897 } 4898 ImGui::BeginChild("Log"); 4899 switch (test_type) 4900 { 4901 case 0: 4902 // Single call to TextUnformatted() with a big buffer 4903 ImGui::TextUnformatted(log.begin(), log.end()); 4904 break; 4905 case 1: 4906 { 4907 // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. 4908 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 4909 ImGuiListClipper clipper; 4910 clipper.Begin(lines); 4911 while (clipper.Step()) 4912 for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) 4913 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 4914 ImGui::PopStyleVar(); 4915 break; 4916 } 4917 case 2: 4918 // Multiple calls to Text(), not clipped (slow) 4919 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 4920 for (int i = 0; i < lines; i++) 3182 4921 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 3183 ImGui::PopStyleVar(); 3184 break; 3185 } 3186 case 2: 3187 // Multiple calls to Text(), not clipped (slow) 3188 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); 3189 for (int i = 0; i < lines; i++) 3190 ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); 3191 ImGui::PopStyleVar(); 3192 break; 3193 } 3194 ImGui::EndChild(); 3195 ImGui::End(); 4922 ImGui::PopStyleVar(); 4923 break; 4924 } 4925 ImGui::EndChild(); 4926 ImGui::End(); 4927 } 4928 4929 //----------------------------------------------------------------------------- 4930 // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() 4931 //----------------------------------------------------------------------------- 4932 4933 // Demonstrate creating a window which gets auto-resized according to its content. 4934 static void ShowExampleAppAutoResize(bool* p_open) 4935 { 4936 if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) 4937 { 4938 ImGui::End(); 4939 return; 4940 } 4941 4942 static int lines = 10; 4943 ImGui::TextUnformatted( 4944 "Window will resize every-frame to the size of its content.\n" 4945 "Note that you probably don't want to query the window size to\n" 4946 "output your content because that would create a feedback loop."); 4947 ImGui::SliderInt("Number of lines", &lines, 1, 20); 4948 for (int i = 0; i < lines; i++) 4949 ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally 4950 ImGui::End(); 4951 } 4952 4953 //----------------------------------------------------------------------------- 4954 // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() 4955 //----------------------------------------------------------------------------- 4956 4957 // Demonstrate creating a window with custom resize constraints. 4958 static void ShowExampleAppConstrainedResize(bool* p_open) 4959 { 4960 struct CustomConstraints 4961 { 4962 // Helper functions to demonstrate programmatic constraints 4963 static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); } 4964 static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } 4965 }; 4966 4967 const char* test_desc[] = 4968 { 4969 "Resize vertical only", 4970 "Resize horizontal only", 4971 "Width > 100, Height > 100", 4972 "Width 400-500", 4973 "Height 400-500", 4974 "Custom: Always Square", 4975 "Custom: Fixed Steps (100)", 4976 }; 4977 4978 static bool auto_resize = false; 4979 static int type = 0; 4980 static int display_lines = 10; 4981 if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only 4982 if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only 4983 if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100 4984 if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500 4985 if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500 4986 if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square 4987 if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step 4988 4989 ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; 4990 if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) 4991 { 4992 if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); 4993 if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); 4994 if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } 4995 ImGui::SetNextItemWidth(200); 4996 ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); 4997 ImGui::SetNextItemWidth(200); 4998 ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); 4999 ImGui::Checkbox("Auto-resize", &auto_resize); 5000 for (int i = 0; i < display_lines; i++) 5001 ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); 5002 } 5003 ImGui::End(); 5004 } 5005 5006 //----------------------------------------------------------------------------- 5007 // [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() 5008 //----------------------------------------------------------------------------- 5009 5010 // Demonstrate creating a simple static window with no decoration 5011 // + a context-menu to choose which corner of the screen to use. 5012 static void ShowExampleAppSimpleOverlay(bool* p_open) 5013 { 5014 const float DISTANCE = 10.0f; 5015 static int corner = 0; 5016 ImGuiIO& io = ImGui::GetIO(); 5017 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; 5018 if (corner != -1) 5019 { 5020 window_flags |= ImGuiWindowFlags_NoMove; 5021 ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE); 5022 ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f); 5023 ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); 5024 } 5025 ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background 5026 if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) 5027 { 5028 ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); 5029 ImGui::Separator(); 5030 if (ImGui::IsMousePosValid()) 5031 ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); 5032 else 5033 ImGui::Text("Mouse Position: <invalid>"); 5034 if (ImGui::BeginPopupContextWindow()) 5035 { 5036 if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; 5037 if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; 5038 if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; 5039 if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; 5040 if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; 5041 if (p_open && ImGui::MenuItem("Close")) *p_open = false; 5042 ImGui::EndPopup(); 5043 } 5044 } 5045 ImGui::End(); 5046 } 5047 5048 //----------------------------------------------------------------------------- 5049 // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() 5050 //----------------------------------------------------------------------------- 5051 5052 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation. 5053 // This apply to all regular items as well. 5054 // Read FAQ section "How can I have multiple widgets with the same label?" for details. 5055 static void ShowExampleAppWindowTitles(bool*) 5056 { 5057 // By default, Windows are uniquely identified by their title. 5058 // You can use the "##" and "###" markers to manipulate the display/ID. 5059 5060 // Using "##" to display same title but have unique identifier. 5061 ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); 5062 ImGui::Begin("Same title as another window##1"); 5063 ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); 5064 ImGui::End(); 5065 5066 ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); 5067 ImGui::Begin("Same title as another window##2"); 5068 ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); 5069 ImGui::End(); 5070 5071 // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" 5072 char buf[128]; 5073 sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); 5074 ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); 5075 ImGui::Begin(buf); 5076 ImGui::Text("This window has a changing title."); 5077 ImGui::End(); 5078 } 5079 5080 //----------------------------------------------------------------------------- 5081 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() 5082 //----------------------------------------------------------------------------- 5083 5084 // Demonstrate using the low-level ImDrawList to draw custom shapes. 5085 static void ShowExampleAppCustomRendering(bool* p_open) 5086 { 5087 if (!ImGui::Begin("Example: Custom rendering", p_open)) 5088 { 5089 ImGui::End(); 5090 return; 5091 } 5092 5093 // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of 5094 // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your 5095 // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not 5096 // exposed outside (to avoid messing with your types) In this example we are not using the maths operators! 5097 5098 if (ImGui::BeginTabBar("##TabBar")) 5099 { 5100 if (ImGui::BeginTabItem("Primitives")) 5101 { 5102 ImGui::PushItemWidth(-ImGui::GetFontSize() * 10); 5103 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 5104 5105 // Draw gradients 5106 // (note that those are currently exacerbating our sRGB/Linear issues) 5107 // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well.. 5108 ImGui::Text("Gradients"); 5109 ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight()); 5110 { 5111 ImVec2 p0 = ImGui::GetCursorScreenPos(); 5112 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); 5113 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255)); 5114 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255)); 5115 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); 5116 ImGui::InvisibleButton("##gradient1", gradient_size); 5117 } 5118 { 5119 ImVec2 p0 = ImGui::GetCursorScreenPos(); 5120 ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y); 5121 ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255)); 5122 ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255)); 5123 draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a); 5124 ImGui::InvisibleButton("##gradient2", gradient_size); 5125 } 5126 5127 // Draw a bunch of primitives 5128 ImGui::Text("All primitives"); 5129 static float sz = 36.0f; 5130 static float thickness = 3.0f; 5131 static int ngon_sides = 6; 5132 static bool circle_segments_override = false; 5133 static int circle_segments_override_v = 12; 5134 static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); 5135 ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); 5136 ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); 5137 ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); 5138 ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); 5139 ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); 5140 if (ImGui::SliderInt("Circle segments", &circle_segments_override_v, 3, 40)) 5141 circle_segments_override = true; 5142 ImGui::ColorEdit4("Color", &colf.x); 5143 5144 const ImVec2 p = ImGui::GetCursorScreenPos(); 5145 const ImU32 col = ImColor(colf); 5146 const float spacing = 10.0f; 5147 const ImDrawCornerFlags corners_none = 0; 5148 const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; 5149 const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; 5150 const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; 5151 float x = p.x + 4.0f; 5152 float y = p.y + 4.0f; 5153 for (int n = 0; n < 2; n++) 5154 { 5155 // First line uses a thickness of 1.0f, second line uses the configurable thickness 5156 float th = (n == 0) ? 1.0f : thickness; 5157 draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon 5158 draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle 5159 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square 5160 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th); x += sz + spacing; // Square with all rounded corners 5161 draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners 5162 draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle 5163 //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle 5164 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) 5165 draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!) 5166 draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line 5167 draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th); 5168 x = p.x + 4; 5169 y += sz + spacing; 5170 } 5171 draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides); x += sz + spacing; // N-gon 5172 draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments); x += sz + spacing; // Circle 5173 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col); x += sz + spacing; // Square 5174 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f); x += sz + spacing; // Square with all rounded corners 5175 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br); x += sz + spacing; // Square with two rounded corners 5176 draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col); x += sz + spacing; // Triangle 5177 //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle 5178 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col); x += sz + spacing; // Horizontal line (faster than AddLine, but only handle integer thickness) 5179 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col); x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness) 5180 draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col); x += sz; // Pixel (faster than AddLine) 5181 draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255)); 5182 5183 ImGui::Dummy(ImVec2((sz + spacing) * 8.8f, (sz + spacing) * 3.0f)); 5184 ImGui::PopItemWidth(); 5185 ImGui::EndTabItem(); 5186 } 5187 5188 if (ImGui::BeginTabItem("Canvas")) 5189 { 5190 static ImVector<ImVec2> points; 5191 static ImVec2 scrolling(0.0f, 0.0f); 5192 static bool opt_enable_grid = true; 5193 static bool opt_enable_context_menu = true; 5194 static bool adding_line = false; 5195 5196 ImGui::Checkbox("Enable grid", &opt_enable_grid); 5197 ImGui::Checkbox("Enable context menu", &opt_enable_context_menu); 5198 ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu."); 5199 5200 // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. 5201 // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. 5202 // To use a child window instead we could use, e.g: 5203 // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding 5204 // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color 5205 // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove); 5206 // ImGui::PopStyleColor(); 5207 // ImGui::PopStyleVar(); 5208 // [...] 5209 // ImGui::EndChild(); 5210 5211 // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() 5212 ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! 5213 ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available 5214 if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f; 5215 if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f; 5216 ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); 5217 5218 // Draw border and background color 5219 ImGuiIO& io = ImGui::GetIO(); 5220 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 5221 draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255)); 5222 draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255)); 5223 5224 // This will catch our interactions 5225 ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); 5226 const bool is_hovered = ImGui::IsItemHovered(); // Hovered 5227 const bool is_active = ImGui::IsItemActive(); // Held 5228 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin 5229 const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y); 5230 5231 // Add first and second point 5232 if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) 5233 { 5234 points.push_back(mouse_pos_in_canvas); 5235 points.push_back(mouse_pos_in_canvas); 5236 adding_line = true; 5237 } 5238 if (adding_line) 5239 { 5240 points.back() = mouse_pos_in_canvas; 5241 if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) 5242 adding_line = false; 5243 } 5244 5245 // Pan (we use a zero mouse threshold when there's no context menu) 5246 // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. 5247 const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f; 5248 if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) 5249 { 5250 scrolling.x += io.MouseDelta.x; 5251 scrolling.y += io.MouseDelta.y; 5252 } 5253 5254 // Context menu (under default mouse threshold) 5255 ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right); 5256 if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f) 5257 ImGui::OpenPopupOnItemClick("context"); 5258 if (ImGui::BeginPopup("context")) 5259 { 5260 if (adding_line) 5261 points.resize(points.size() - 2); 5262 adding_line = false; 5263 if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); } 5264 if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); } 5265 ImGui::EndPopup(); 5266 } 5267 5268 // Draw grid + all lines in the canvas 5269 draw_list->PushClipRect(canvas_p0, canvas_p1, true); 5270 if (opt_enable_grid) 5271 { 5272 const float GRID_STEP = 64.0f; 5273 for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP) 5274 draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40)); 5275 for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP) 5276 draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40)); 5277 } 5278 for (int n = 0; n < points.Size; n += 2) 5279 draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f); 5280 draw_list->PopClipRect(); 5281 5282 ImGui::EndTabItem(); 5283 } 5284 5285 if (ImGui::BeginTabItem("BG/FG draw lists")) 5286 { 5287 static bool draw_bg = true; 5288 static bool draw_fg = true; 5289 ImGui::Checkbox("Draw in Background draw list", &draw_bg); 5290 ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows."); 5291 ImGui::Checkbox("Draw in Foreground draw list", &draw_fg); 5292 ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows."); 5293 ImVec2 window_pos = ImGui::GetWindowPos(); 5294 ImVec2 window_size = ImGui::GetWindowSize(); 5295 ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f); 5296 if (draw_bg) 5297 ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4); 5298 if (draw_fg) 5299 ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10); 5300 ImGui::EndTabItem(); 5301 } 5302 5303 ImGui::EndTabBar(); 5304 } 5305 5306 ImGui::End(); 5307 } 5308 5309 //----------------------------------------------------------------------------- 5310 // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() 5311 //----------------------------------------------------------------------------- 5312 5313 // Simplified structure to mimic a Document model 5314 struct MyDocument 5315 { 5316 const char* Name; // Document title 5317 bool Open; // Set when open (we keep an array of all available documents to simplify demo code!) 5318 bool OpenPrev; // Copy of Open from last update. 5319 bool Dirty; // Set when the document has been modified 5320 bool WantClose; // Set when the document 5321 ImVec4 Color; // An arbitrary variable associated to the document 5322 5323 MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)) 5324 { 5325 Name = name; 5326 Open = OpenPrev = open; 5327 Dirty = false; 5328 WantClose = false; 5329 Color = color; 5330 } 5331 void DoOpen() { Open = true; } 5332 void DoQueueClose() { WantClose = true; } 5333 void DoForceClose() { Open = false; Dirty = false; } 5334 void DoSave() { Dirty = false; } 5335 5336 // Display placeholder contents for the Document 5337 static void DisplayContents(MyDocument* doc) 5338 { 5339 ImGui::PushID(doc); 5340 ImGui::Text("Document \"%s\"", doc->Name); 5341 ImGui::PushStyleColor(ImGuiCol_Text, doc->Color); 5342 ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); 5343 ImGui::PopStyleColor(); 5344 if (ImGui::Button("Modify", ImVec2(100, 0))) 5345 doc->Dirty = true; 5346 ImGui::SameLine(); 5347 if (ImGui::Button("Save", ImVec2(100, 0))) 5348 doc->DoSave(); 5349 ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior. 5350 ImGui::PopID(); 5351 } 5352 5353 // Display context menu for the Document 5354 static void DisplayContextMenu(MyDocument* doc) 5355 { 5356 if (!ImGui::BeginPopupContextItem()) 5357 return; 5358 5359 char buf[256]; 5360 sprintf(buf, "Save %s", doc->Name); 5361 if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open)) 5362 doc->DoSave(); 5363 if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open)) 5364 doc->DoQueueClose(); 5365 ImGui::EndPopup(); 5366 } 5367 }; 5368 5369 struct ExampleAppDocuments 5370 { 5371 ImVector<MyDocument> Documents; 5372 5373 ExampleAppDocuments() 5374 { 5375 Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f))); 5376 Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f))); 5377 Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f))); 5378 Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f))); 5379 Documents.push_back(MyDocument("A Rather Long Title", false)); 5380 Documents.push_back(MyDocument("Some Document", false)); 5381 } 5382 }; 5383 5384 // [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface. 5385 // If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, 5386 // as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for 5387 // the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has 5388 // disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively 5389 // give the impression of a flicker for one frame. 5390 // We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch. 5391 // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. 5392 static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) 5393 { 5394 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5395 { 5396 MyDocument* doc = &app.Documents[doc_n]; 5397 if (!doc->Open && doc->OpenPrev) 5398 ImGui::SetTabItemClosed(doc->Name); 5399 doc->OpenPrev = doc->Open; 5400 } 5401 } 5402 5403 void ShowExampleAppDocuments(bool* p_open) 5404 { 5405 static ExampleAppDocuments app; 5406 5407 // Options 5408 static bool opt_reorderable = true; 5409 static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; 5410 5411 bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); 5412 if (!window_contents_visible) 5413 { 5414 ImGui::End(); 5415 return; 5416 } 5417 5418 // Menu 5419 if (ImGui::BeginMenuBar()) 5420 { 5421 if (ImGui::BeginMenu("File")) 5422 { 5423 int open_count = 0; 5424 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5425 open_count += app.Documents[doc_n].Open ? 1 : 0; 5426 5427 if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) 5428 { 5429 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5430 { 5431 MyDocument* doc = &app.Documents[doc_n]; 5432 if (!doc->Open) 5433 if (ImGui::MenuItem(doc->Name)) 5434 doc->DoOpen(); 5435 } 5436 ImGui::EndMenu(); 5437 } 5438 if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) 5439 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5440 app.Documents[doc_n].DoQueueClose(); 5441 if (ImGui::MenuItem("Exit", "Alt+F4")) {} 5442 ImGui::EndMenu(); 5443 } 5444 ImGui::EndMenuBar(); 5445 } 5446 5447 // [Debug] List documents with one checkbox for each 5448 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5449 { 5450 MyDocument* doc = &app.Documents[doc_n]; 5451 if (doc_n > 0) 5452 ImGui::SameLine(); 5453 ImGui::PushID(doc); 5454 if (ImGui::Checkbox(doc->Name, &doc->Open)) 5455 if (!doc->Open) 5456 doc->DoForceClose(); 5457 ImGui::PopID(); 5458 } 5459 5460 ImGui::Separator(); 5461 5462 // Submit Tab Bar and Tabs 5463 { 5464 ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); 5465 if (ImGui::BeginTabBar("##tabs", tab_bar_flags)) 5466 { 5467 if (opt_reorderable) 5468 NotifyOfDocumentsClosedElsewhere(app); 5469 5470 // [DEBUG] Stress tests 5471 //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on. 5472 //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. 5473 5474 // Submit Tabs 5475 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5476 { 5477 MyDocument* doc = &app.Documents[doc_n]; 5478 if (!doc->Open) 5479 continue; 5480 5481 ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); 5482 bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); 5483 5484 // Cancel attempt to close when unsaved add to save queue so we can display a popup. 5485 if (!doc->Open && doc->Dirty) 5486 { 5487 doc->Open = true; 5488 doc->DoQueueClose(); 5489 } 5490 5491 MyDocument::DisplayContextMenu(doc); 5492 if (visible) 5493 { 5494 MyDocument::DisplayContents(doc); 5495 ImGui::EndTabItem(); 5496 } 5497 } 5498 5499 ImGui::EndTabBar(); 5500 } 5501 } 5502 5503 // Update closing queue 5504 static ImVector<MyDocument*> close_queue; 5505 if (close_queue.empty()) 5506 { 5507 // Close queue is locked once we started a popup 5508 for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) 5509 { 5510 MyDocument* doc = &app.Documents[doc_n]; 5511 if (doc->WantClose) 5512 { 5513 doc->WantClose = false; 5514 close_queue.push_back(doc); 5515 } 5516 } 5517 } 5518 5519 // Display closing confirmation UI 5520 if (!close_queue.empty()) 5521 { 5522 int close_queue_unsaved_documents = 0; 5523 for (int n = 0; n < close_queue.Size; n++) 5524 if (close_queue[n]->Dirty) 5525 close_queue_unsaved_documents++; 5526 5527 if (close_queue_unsaved_documents == 0) 5528 { 5529 // Close documents when all are unsaved 5530 for (int n = 0; n < close_queue.Size; n++) 5531 close_queue[n]->DoForceClose(); 5532 close_queue.clear(); 5533 } 5534 else 5535 { 5536 if (!ImGui::IsPopupOpen("Save?")) 5537 ImGui::OpenPopup("Save?"); 5538 if (ImGui::BeginPopupModal("Save?")) 5539 { 5540 ImGui::Text("Save change to the following items?"); 5541 ImGui::SetNextItemWidth(-1.0f); 5542 if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) 5543 { 5544 for (int n = 0; n < close_queue.Size; n++) 5545 if (close_queue[n]->Dirty) 5546 ImGui::Text("%s", close_queue[n]->Name); 5547 ImGui::ListBoxFooter(); 5548 } 5549 5550 if (ImGui::Button("Yes", ImVec2(80, 0))) 5551 { 5552 for (int n = 0; n < close_queue.Size; n++) 5553 { 5554 if (close_queue[n]->Dirty) 5555 close_queue[n]->DoSave(); 5556 close_queue[n]->DoForceClose(); 5557 } 5558 close_queue.clear(); 5559 ImGui::CloseCurrentPopup(); 5560 } 5561 ImGui::SameLine(); 5562 if (ImGui::Button("No", ImVec2(80, 0))) 5563 { 5564 for (int n = 0; n < close_queue.Size; n++) 5565 close_queue[n]->DoForceClose(); 5566 close_queue.clear(); 5567 ImGui::CloseCurrentPopup(); 5568 } 5569 ImGui::SameLine(); 5570 if (ImGui::Button("Cancel", ImVec2(80, 0))) 5571 { 5572 close_queue.clear(); 5573 ImGui::CloseCurrentPopup(); 5574 } 5575 ImGui::EndPopup(); 5576 } 5577 } 5578 } 5579 5580 ImGui::End(); 3196 5581 } 3197 5582 … … 3199 5584 #else 3200 5585 5586 void ImGui::ShowAboutWindow(bool*) {} 3201 5587 void ImGui::ShowDemoWindow(bool*) {} 3202 5588 void ImGui::ShowUserGuide() {} … … 3204 5590 3205 5591 #endif 5592 5593 #endif // #ifndef IMGUI_DISABLE
Note:
See TracChangeset
for help on using the changeset viewer.