30 | | - ISSUES & TODO LIST |
31 | | - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS |
32 | | - How can I tell whether to dispatch mouse/keyboard to imgui or to my application? |
33 | | - How can I display an image? What is ImTextureID, how does it works? |
34 | | - How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack. |
35 | | - How can I load a different font than the default? |
36 | | - How can I easily use icons in my application? |
37 | | - How can I load multiple fonts? |
38 | | - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? |
39 | | - How can I use the drawing facilities without an ImGui window? (using ImDrawList API) |
40 | | - I integrated Dear ImGui in my engine and the text or lines are blurry.. |
41 | | - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. |
42 | | - How can I help? |
43 | | - ISSUES & TODO-LIST |
44 | | - CODE |
45 | | |
46 | | |
47 | | MISSION STATEMENT |
48 | | ================= |
49 | | |
50 | | - Easy to use to create code-driven and data-driven tools |
51 | | - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools |
52 | | - Easy to hack and improve |
53 | | - Minimize screen real-estate usage |
54 | | - Minimize setup and maintenance |
55 | | - Minimize state storage on user side |
56 | | - Portable, minimize dependencies, run on target (consoles, phones, etc.) |
57 | | - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window, |
58 | | opening a tree node for the first time, etc. but a typical frame should not allocate anything) |
59 | | |
60 | | Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes: |
61 | | - Doesn't look fancy, doesn't animate |
62 | | - Limited layout features, intricate layouts are typically crafted in code |
63 | | |
64 | | |
65 | | END-USER GUIDE |
66 | | ============== |
67 | | |
68 | | - Double-click on title bar to collapse window. |
69 | | - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). |
70 | | - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). |
71 | | - Click and drag on any empty space to move window. |
72 | | - TAB/SHIFT+TAB to cycle through keyboard editable fields. |
73 | | - CTRL+Click on a slider or drag box to input value as text. |
74 | | - Use mouse wheel to scroll. |
75 | | - Text editor: |
76 | | - Hold SHIFT or use mouse to select text. |
77 | | - CTRL+Left/Right to word jump. |
78 | | - CTRL+Shift+Left/Right to select words. |
79 | | - CTRL+A our Double-Click to select all. |
80 | | - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ |
81 | | - CTRL+Z,CTRL+Y to undo/redo. |
82 | | - ESCAPE to revert text to its original value. |
83 | | - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) |
84 | | - Controls are automatically adjusted for OSX to match standard OSX text editing operations. |
85 | | - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. |
86 | | - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW |
87 | | |
88 | | |
89 | | PROGRAMMER GUIDE |
90 | | ================ |
91 | | |
92 | | READ FIRST |
93 | | |
94 | | - Read the FAQ below this section! |
95 | | - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction |
96 | | or destruction steps, less data retention on your side, less state duplication, less state synchronization, less bugs. |
97 | | - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. |
98 | | - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861 |
99 | | |
100 | | HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI |
101 | | |
102 | | - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) |
103 | | - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. |
104 | | If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed |
105 | | from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will |
106 | | likely be a comment about it. Please report any issue to the GitHub page! |
107 | | - Try to keep your copy of dear imgui reasonably up to date. |
108 | | |
109 | | GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE |
110 | | |
111 | | - Run and study the examples and demo to get acquainted with the library. |
112 | | - Add the Dear ImGui source files to your projects, using your preferred build system. |
113 | | It is recommended you build the .cpp files as part of your project and not as a library. |
114 | | - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types. |
115 | | - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/ folder. |
116 | | - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. |
117 | | |
118 | | - Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize |
119 | | (application resolution). Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic |
120 | | integration you don't need to worry about it all. |
121 | | - Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory. |
122 | | - Every frame: |
123 | | - In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.) |
124 | | - Call ImGui::NewFrame() to begin the frame |
125 | | - You can use any ImGui function you want between NewFrame() and Render() |
126 | | - Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler. |
127 | | (Even if you don't render, call Render() and ignore the callback, or call EndFrame() instead. Otherwise some features will break) |
128 | | - All rendering information are stored into command-lists until ImGui::Render() is called. |
129 | | - Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide. |
130 | | - Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases |
131 | | of your own application. |
132 | | - Refer to the examples applications in the examples/ folder for instruction on how to setup your code. |
133 | | - A minimal application skeleton may be: |
134 | | |
135 | | // Application init |
136 | | ImGui::CreateContext(); |
137 | | ImGuiIO& io = ImGui::GetIO(); |
138 | | io.DisplaySize.x = 1920.0f; |
139 | | io.DisplaySize.y = 1280.0f; |
140 | | // TODO: Fill others settings of the io structure later. |
141 | | |
142 | | // Load texture atlas (there is a default font so you don't need to care about choosing a font yet) |
143 | | unsigned char* pixels; |
144 | | int width, height; |
145 | | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); |
146 | | // TODO: At this points you've got the texture data and you need to upload that your your graphic system: |
147 | | MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA) |
148 | | // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer. |
149 | | io.Fonts->TexID = (void*)texture; |
150 | | |
151 | | // Application main loop |
152 | | while (true) |
153 | | { |
154 | | // Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or write to those fields from your Windows message loop handlers, etc.) |
155 | | ImGuiIO& io = ImGui::GetIO(); |
156 | | io.DeltaTime = 1.0f/60.0f; |
157 | | io.MousePos = mouse_pos; |
158 | | io.MouseDown[0] = mouse_button_0; |
159 | | io.MouseDown[1] = mouse_button_1; |
160 | | |
161 | | // Call NewFrame(), after this point you can use ImGui::* functions anytime |
162 | | ImGui::NewFrame(); |
163 | | |
164 | | // Most of your application code here |
165 | | MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); |
166 | | MyGameRender(); // may use any ImGui functions as well! |
167 | | |
168 | | // Render & swap video buffers |
169 | | ImGui::Render(); |
170 | | MyImGuiRenderFunction(ImGui::GetDrawData()); |
171 | | SwapBuffers(); |
172 | | } |
173 | | |
174 | | // Shutdown |
175 | | ImGui::DestroyContext(); |
176 | | |
177 | | |
178 | | - A minimal render function skeleton may be: |
179 | | |
180 | | void void MyRenderFunction(ImDrawData* draw_data) |
181 | | { |
182 | | // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled |
183 | | // TODO: Setup viewport, orthographic projection matrix |
184 | | // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. |
185 | | for (int n = 0; n < draw_data->CmdListsCount; n++) |
186 | | { |
187 | | const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui |
188 | | const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui |
189 | | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) |
190 | | { |
191 | | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; |
192 | | if (pcmd->UserCallback) |
193 | | { |
194 | | pcmd->UserCallback(cmd_list, pcmd); |
195 | | } |
196 | | else |
197 | | { |
198 | | // The texture for the draw call is specified by pcmd->TextureId. |
199 | | // The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization. |
200 | | MyEngineBindTexture(pcmd->TextureId); |
201 | | |
202 | | // We are using scissoring to clip some objects. All low-level graphics API supports it. |
203 | | // If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches |
204 | | // (some elements visible outside their bounds) but you can fix that once everywhere else works! |
205 | | MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); |
206 | | |
207 | | // Render 'pcmd->ElemCount/3' indexed triangles. |
208 | | // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices. |
209 | | MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); |
210 | | } |
211 | | idx_buffer += pcmd->ElemCount; |
212 | | } |
213 | | } |
214 | | } |
215 | | |
216 | | - The examples/ folders contains many functional implementation of the pseudo-code above. |
217 | | - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated. |
218 | | They tell you if ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the rest of your application. |
219 | | However, in both cases you need to pass on the inputs to imgui. Read the FAQ below for more information about those flags. |
220 | | - Please read the FAQ above. Amusingly, it is called a FAQ because people frequently have the same issues! |
221 | | |
222 | | USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS [BETA] |
223 | | |
224 | | - The gamepad/keyboard navigation is in Beta. Ask questions and report issues at https://github.com/ocornut/imgui/issues/787 |
225 | | - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. |
226 | | - Gamepad: |
227 | | - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. |
228 | | - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). |
229 | | Note that io.NavInputs[] is cleared by EndFrame(). |
230 | | - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: |
231 | | 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. |
232 | | - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. |
233 | | Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). |
234 | | - You can download PNG/PSD files depicting the gamepad controls for common controllers at: goo.gl/9LgVZW. |
235 | | - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo |
236 | | to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. |
237 | | - Keyboard: |
238 | | - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. |
239 | | NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. |
240 | | - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag |
241 | | will be set. For more advanced uses, you may want to read from: |
242 | | - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. |
243 | | - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). |
244 | | - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. |
245 | | Please reach out if you think the game vs navigation input sharing could be improved. |
246 | | - Mouse: |
247 | | - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. |
248 | | - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. |
249 | | - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. |
250 | | Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. |
251 | | When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. |
252 | | When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that. |
253 | | (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!) |
254 | | (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want |
255 | | to set a boolean to ignore your other external mouse positions until the external source is moved again.) |
256 | | |
257 | | |
258 | | API BREAKING CHANGES |
259 | | ==================== |
260 | | |
261 | | Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. |
262 | | Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. |
263 | | Also read releases logs https://github.com/ocornut/imgui/releases for more details. |
264 | | |
265 | | - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", consistent with other functions. Kept redirection functions (will obsolete). |
266 | | - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. |
267 | | - 2018/03/20 (1.60) - Renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). |
268 | | - 2018/03/12 (1.60) - Removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. |
269 | | - 2018/03/08 (1.60) - Changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. |
270 | | - 2018/03/03 (1.60) - Renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. |
271 | | - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment. |
272 | | - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display. |
273 | | - 2018/02/07 (1.60) - reorganized context handling to be more explicit, |
274 | | - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. |
275 | | - removed Shutdown() function, as DestroyContext() serve this purpose. |
276 | | - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. |
277 | | - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. |
278 | | - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. |
279 | | - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths. |
280 | | - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). |
281 | | - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). |
282 | | - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. |
283 | | - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side. |
284 | | - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). |
285 | | - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags |
286 | | - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame. |
287 | | - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. |
288 | | - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). |
289 | | - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). |
290 | | - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). |
291 | | - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). |
292 | | - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). |
293 | | - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed. |
294 | | - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up. |
295 | | Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions. |
296 | | - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. |
297 | | - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. |
298 | | - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. |
299 | | - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); |
300 | | - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency. |
301 | | - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. |
302 | | - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details. |
303 | | removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. |
304 | | - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! |
305 | | - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). |
306 | | - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). |
307 | | - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". |
308 | | - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! |
309 | | - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). |
310 | | - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). |
311 | | - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. |
312 | | - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. |
313 | | - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame. |
314 | | - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. |
315 | | - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete). |
316 | | - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete). |
317 | | - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). |
318 | | - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. |
319 | | - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. |
320 | | - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))' |
321 | | - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse |
322 | | - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. |
323 | | - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. |
324 | | - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). |
325 | | - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. |
326 | | - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. |
327 | | - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. |
328 | | - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. |
329 | | If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. |
330 | | However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. |
331 | | This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. |
332 | | ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) |
333 | | { |
334 | | float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; |
335 | | return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); |
336 | | } |
337 | | If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. |
338 | | - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). |
339 | | - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. |
340 | | - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). |
341 | | - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. |
342 | | - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). |
343 | | - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) |
344 | | - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). |
345 | | - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. |
346 | | - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. |
347 | | - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. |
348 | | - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. |
349 | | - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. |
350 | | GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side. |
351 | | GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out! |
352 | | - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize |
353 | | - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project. |
354 | | - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason |
355 | | - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. |
356 | | you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. |
357 | | - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. |
358 | | this necessary change will break your rendering function! the fix should be very easy. sorry for that :( |
359 | | - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. |
360 | | - the signature of the io.RenderDrawListsFn handler has changed! |
361 | | old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) |
362 | | new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). |
363 | | argument: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' |
364 | | ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. |
365 | | ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. |
366 | | - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. |
367 | | - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering! |
368 | | - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! |
369 | | - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. |
370 | | - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). |
371 | | - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. |
372 | | - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence |
373 | | - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! |
374 | | - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). |
375 | | - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). |
376 | | - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. |
377 | | - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. |
378 | | - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). |
379 | | - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. |
380 | | - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API |
381 | | - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. |
382 | | - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. |
383 | | - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. |
384 | | - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing |
385 | | - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. |
386 | | - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) |
387 | | - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. |
388 | | - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. |
389 | | - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. |
390 | | - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior |
391 | | - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() |
392 | | - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) |
393 | | - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. |
394 | | - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. |
395 | | (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. |
396 | | font init: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..> |
397 | | became: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; |
398 | | you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. |
399 | | it is now recommended that you sample the font texture with bilinear interpolation. |
400 | | (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. |
401 | | (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) |
402 | | (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets |
403 | | - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) |
404 | | - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) |
405 | | - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility |
406 | | - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() |
407 | | - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly) |
408 | | - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) |
409 | | - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() |
410 | | - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn |
411 | | - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) |
412 | | - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite |
413 | | - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes |
414 | | |
415 | | |
416 | | ISSUES & TODO-LIST |
417 | | ================== |
418 | | See TODO.txt |
419 | | |
420 | | |
421 | | FREQUENTLY ASKED QUESTIONS (FAQ), TIPS |
422 | | ====================================== |
423 | | |
424 | | Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application? |
425 | | A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure. |
426 | | - When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application. |
427 | | - When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application. |
428 | | - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS). |
429 | | Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false. |
430 | | This is because imgui needs to detect that you clicked in the void to unfocus its windows. |
431 | | Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!). |
432 | | It handle mouse dragging correctly (both dragging that started over your application or over an imgui window) and handle e.g. modal windows blocking inputs. |
433 | | Those flags are updated by ImGui::NewFrame(). Preferably read the flags after calling NewFrame() if you can afford it, but reading them before is also |
434 | | perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to NewFrameUpdateHoveredWindowAndCaptureFlags(). |
435 | | Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically |
436 | | have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs |
437 | | were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) |
438 | | |
439 | | Q: How can I display an image? What is ImTextureID, how does it works? |
440 | | A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function. |
441 | | Dear ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry! |
442 | | It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc. |
443 | | At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render. |
444 | | Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing. |
445 | | (C++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!) |
446 | | To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions. |
447 | | Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use. |
448 | | You may call ImGui::ShowMetricsWindow() to explore active draw lists and visualize/understand how the draw data is generated. |
449 | | It is your responsibility to get textures uploaded to your GPU. |
450 | | |
451 | | Q: How can I have multiple widgets with the same label or without a label? |
452 | | A: A primer on labels and the ID Stack... |
453 | | |
454 | | - Elements that are typically not clickable, such as Text() items don't need an ID. |
455 | | |
456 | | - Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui |
457 | | often needs to remember what is the "active" widget). To do so they need a unique ID. Unique ID |
458 | | are typically derived from a string label, an integer index or a pointer. |
459 | | |
460 | | Button("OK"); // Label = "OK", ID = top of id stack + hash of "OK" |
461 | | Button("Cancel"); // Label = "Cancel", ID = top of id stack + hash of "Cancel" |
462 | | |
463 | | - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having |
464 | | two buttons labeled "OK" in different windows or different tree locations is fine. |
465 | | |
466 | | - If you have a same ID twice in the same location, you'll have a conflict: |
467 | | |
468 | | Button("OK"); |
469 | | Button("OK"); // ID collision! Interacting with either button will trigger the first one. |
470 | | |
471 | | Fear not! this is easy to solve and there are many ways to solve it! |
472 | | |
473 | | - Solving ID conflict in a simple/local context: |
474 | | When passing a label you can optionally specify extra ID information within string itself. |
475 | | Use "##" to pass a complement to the ID that won't be visible to the end-user. |
476 | | This helps solving the simple collision cases when you know e.g. at compilation time which items |
477 | | are going to be created: |
478 | | |
479 | | Button("Play"); // Label = "Play", ID = top of id stack + hash of "Play" |
480 | | Button("Play##foo1"); // Label = "Play", ID = top of id stack + hash of "Play##foo1" (different from above) |
481 | | Button("Play##foo2"); // Label = "Play", ID = top of id stack + hash of "Play##foo2" (different from above) |
482 | | |
483 | | - If you want to completely hide the label, but still need an ID: |
484 | | |
485 | | Checkbox("##On", &b); // Label = "", ID = top of id stack + hash of "##On" (no label!) |
486 | | |
487 | | - Occasionally/rarely you might want change a label while preserving a constant ID. This allows |
488 | | you to animate labels. For example you may want to include varying information in a window title bar, |
489 | | but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID: |
490 | | |
491 | | Button("Hello###ID"; // Label = "Hello", ID = top of id stack + hash of "ID" |
492 | | Button("World###ID"; // Label = "World", ID = top of id stack + hash of "ID" (same as above) |
493 | | |
494 | | sprintf(buf, "My game (%f FPS)###MyGame", fps); |
495 | | Begin(buf); // Variable label, ID = hash of "MyGame" |
496 | | |
497 | | - Solving ID conflict in a more general manner: |
498 | | Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts |
499 | | within the same window. This is the most convenient way of distinguishing ID when iterating and |
500 | | creating many UI elements programmatically. |
501 | | You can push a pointer, a string or an integer value into the ID stack. |
502 | | Remember that ID are formed from the concatenation of _everything_ in the ID stack! |
503 | | |
504 | | for (int i = 0; i < 100; i++) |
505 | | { |
506 | | PushID(i); |
507 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of integer + hash of "Click" |
508 | | PopID(); |
509 | | } |
510 | | |
511 | | for (int i = 0; i < 100; i++) |
512 | | { |
513 | | MyObject* obj = Objects[i]; |
514 | | PushID(obj); |
515 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of pointer + hash of "Click" |
516 | | PopID(); |
517 | | } |
518 | | |
519 | | for (int i = 0; i < 100; i++) |
520 | | { |
521 | | MyObject* obj = Objects[i]; |
522 | | PushID(obj->Name); |
523 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of string + hash of "Click" |
524 | | PopID(); |
525 | | } |
526 | | |
527 | | - More example showing that you can stack multiple prefixes into the ID stack: |
528 | | |
529 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click" |
530 | | PushID("node"); |
531 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click" |
532 | | PushID(my_ptr); |
533 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of ptr + hash of "Click" |
534 | | PopID(); |
535 | | PopID(); |
536 | | |
537 | | - Tree nodes implicitly creates a scope for you by calling PushID(). |
538 | | |
539 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click" |
540 | | if (TreeNode("node")) |
541 | | { |
542 | | Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click" |
543 | | TreePop(); |
544 | | } |
545 | | |
546 | | - When working with trees, ID are used to preserve the open/close state of each tree node. |
547 | | Depending on your use cases you may want to use strings, indices or pointers as ID. |
548 | | e.g. when following a single pointer that may change over time, using a static string as ID |
549 | | will preserve your node open/closed state when the targeted object change. |
550 | | e.g. when displaying a list of objects, using indices or pointers as ID will preserve the |
551 | | node open/closed state differently. See what makes more sense in your situation! |
552 | | |
553 | | Q: How can I load a different font than the default? |
554 | | A: Use the font atlas to load the TTF/OTF file you want: |
555 | | ImGuiIO& io = ImGui::GetIO(); |
556 | | io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); |
557 | | io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() |
558 | | (default is ProggyClean.ttf, rendered at size 13, embedded in dear imgui's source code) |
559 | | |
560 | | New programmers: remember that in C/C++ and most programming languages if you want to use a |
561 | | backslash \ within a string literal, you need to write it double backslash "\\": |
562 | | io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG (you are escape the M here!) |
563 | | io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT |
564 | | io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT |
565 | | |
566 | | Q: How can I easily use icons in my application? |
567 | | A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you |
568 | | main font. Then you can refer to icons within your strings. Read 'How can I load multiple fonts?' |
569 | | and the file 'misc/fonts/README.txt' for instructions and useful header files. |
570 | | |
571 | | Q: How can I load multiple fonts? |
572 | | A: Use the font atlas to pack them into a single texture: |
573 | | (Read misc/fonts/README.txt and the code in ImFontAtlas for more details.) |
574 | | |
575 | | ImGuiIO& io = ImGui::GetIO(); |
576 | | ImFont* font0 = io.Fonts->AddFontDefault(); |
577 | | ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); |
578 | | ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels); |
579 | | io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() |
580 | | // the first loaded font gets used by default |
581 | | // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime |
582 | | |
583 | | // Options |
584 | | ImFontConfig config; |
585 | | config.OversampleH = 3; |
586 | | config.OversampleV = 1; |
587 | | config.GlyphOffset.y -= 2.0f; // Move everything by 2 pixels up |
588 | | config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters |
589 | | io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config); |
590 | | |
591 | | // Combine multiple fonts into one (e.g. for icon fonts) |
592 | | ImWchar ranges[] = { 0xf000, 0xf3ff, 0 }; |
593 | | ImFontConfig config; |
594 | | config.MergeMode = true; |
595 | | io.Fonts->AddFontDefault(); |
596 | | io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font |
597 | | io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs |
598 | | |
599 | | Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? |
600 | | A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. |
601 | | |
602 | | // Add default Japanese ranges |
603 | | io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); |
604 | | |
605 | | // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need) |
606 | | ImVector<ImWchar> ranges; |
607 | | ImFontAtlas::GlyphRangesBuilder builder; |
608 | | builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) |
609 | | builder.AddChar(0x7262); // Add a specific character |
610 | | builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges |
611 | | builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) |
612 | | io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); |
613 | | |
614 | | All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 |
615 | | by using the u8"hello" syntax. Specifying literal in your source code using a local code page |
616 | | (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work! |
617 | | Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8. |
618 | | |
619 | | Text input: it is up to your application to pass the right character code by calling |
620 | | io.AddInputCharacter(). The applications in examples/ are doing that. For languages relying |
621 | | on an Input Method Editor (IME), on Windows you can copy the Hwnd of your application in the |
622 | | io.ImeWindowHandle field. The default implementation of io.ImeSetInputScreenPosFn() will set |
623 | | your Microsoft IME position correctly. |
624 | | |
625 | | Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API) |
626 | | A: - You can create a dummy window. Call SetNextWindowBgAlpha(0.0f), call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flags. |
627 | | Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like. |
628 | | - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows. |
629 | | - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData. |
630 | | |
631 | | Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. |
632 | | A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f). |
633 | | Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension. |
634 | | |
635 | | Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. |
636 | | A: You are probably mishandling the clipping rectangles in your render function. |
637 | | Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height). |
638 | | |
639 | | Q: How can I help? |
640 | | A: - If you are experienced with Dear ImGui and C++, look at the github issues, or TODO.txt and see how you want/can help! |
641 | | - Convince your company to fund development time! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README. |
642 | | - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. |
643 | | You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers. |
644 | | But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. |
645 | | - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately). |
646 | | |
647 | | - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. |
648 | | this is also useful to set yourself in the context of another window (to get/set other settings) |
649 | | - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug". |
650 | | - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle |
651 | | of a deep nested inner loop in your code. |
652 | | - tip: you can call Render() multiple times (e.g for VR renders). |
653 | | - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui! |
| 47 | - FREQUENTLY ASKED QUESTIONS (FAQ) |
| 48 | - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer) |
| 49 | |
| 50 | CODE |
| 51 | (search for "[SECTION]" in the code to find them) |
| 52 | |
| 53 | // [SECTION] INCLUDES |
| 54 | // [SECTION] FORWARD DECLARATIONS |
| 55 | // [SECTION] CONTEXT AND MEMORY ALLOCATORS |
| 56 | // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) |
| 57 | // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) |
| 58 | // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) |
| 59 | // [SECTION] MISC HELPERS/UTILITIES (File functions) |
| 60 | // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) |
| 61 | // [SECTION] MISC HELPERS/UTILITIES (Color functions) |
| 62 | // [SECTION] ImGuiStorage |
| 63 | // [SECTION] ImGuiTextFilter |
| 64 | // [SECTION] ImGuiTextBuffer |
| 65 | // [SECTION] ImGuiListClipper |
| 66 | // [SECTION] STYLING |
| 67 | // [SECTION] RENDER HELPERS |
| 68 | // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) |
| 69 | // [SECTION] ERROR CHECKING |
| 70 | // [SECTION] LAYOUT |
| 71 | // [SECTION] SCROLLING |
| 72 | // [SECTION] TOOLTIPS |
| 73 | // [SECTION] POPUPS |
| 74 | // [SECTION] KEYBOARD/GAMEPAD NAVIGATION |
| 75 | // [SECTION] DRAG AND DROP |
| 76 | // [SECTION] LOGGING/CAPTURING |
| 77 | // [SECTION] SETTINGS |
| 78 | // [SECTION] PLATFORM DEPENDENT HELPERS |
| 79 | // [SECTION] METRICS/DEBUG WINDOW |
| 82 | |
| 83 | //----------------------------------------------------------------------------- |
| 84 | // DOCUMENTATION |
| 85 | //----------------------------------------------------------------------------- |
| 86 | |
| 87 | /* |
| 88 | |
| 89 | MISSION STATEMENT |
| 90 | ================= |
| 91 | |
| 92 | - Easy to use to create code-driven and data-driven tools. |
| 93 | - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. |
| 94 | - Easy to hack and improve. |
| 95 | - Minimize setup and maintenance. |
| 96 | - Minimize state storage on user side. |
| 97 | - Portable, minimize dependencies, run on target (consoles, phones, etc.). |
| 98 | - Efficient runtime and memory consumption. |
| 99 | |
| 100 | Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes: |
| 101 | |
| 102 | - Doesn't look fancy, doesn't animate. |
| 103 | - Limited layout features, intricate layouts are typically crafted in code. |
| 104 | |
| 105 | |
| 106 | END-USER GUIDE |
| 107 | ============== |
| 108 | |
| 109 | - Double-click on title bar to collapse window. |
| 110 | - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin(). |
| 111 | - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents). |
| 112 | - Click and drag on any empty space to move window. |
| 113 | - TAB/SHIFT+TAB to cycle through keyboard editable fields. |
| 114 | - CTRL+Click on a slider or drag box to input value as text. |
| 115 | - Use mouse wheel to scroll. |
| 116 | - Text editor: |
| 117 | - Hold SHIFT or use mouse to select text. |
| 118 | - CTRL+Left/Right to word jump. |
| 119 | - CTRL+Shift+Left/Right to select words. |
| 120 | - CTRL+A our Double-Click to select all. |
| 121 | - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ |
| 122 | - CTRL+Z,CTRL+Y to undo/redo. |
| 123 | - ESCAPE to revert text to its original value. |
| 124 | - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!) |
| 125 | - Controls are automatically adjusted for OSX to match standard OSX text editing operations. |
| 126 | - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. |
| 127 | - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW |
| 128 | |
| 129 | |
| 130 | PROGRAMMER GUIDE |
| 131 | ================ |
| 132 | |
| 133 | READ FIRST |
| 134 | ---------- |
| 135 | - Remember to read the FAQ (https://www.dearimgui.org/faq) |
| 136 | - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction |
| 137 | or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs. |
| 138 | - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. |
| 139 | - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. |
| 140 | - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). |
| 141 | You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ. |
| 142 | - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. |
| 143 | For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI, |
| 144 | where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. |
| 145 | - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. |
| 146 | - This codebase is also optimized to yield decent performances with typical "Debug" builds settings. |
| 147 | - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). |
| 148 | If you get an assert, read the messages and comments around the assert. |
| 149 | - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace. |
| 150 | - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. |
| 151 | See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. |
| 152 | However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase. |
| 153 | - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!). |
| 154 | |
| 155 | |
| 156 | HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI |
| 157 | ---------------------------------------------- |
| 158 | - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h) |
| 159 | - Or maintain your own branch where you have imconfig.h modified. |
| 160 | - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. |
| 161 | If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed |
| 162 | from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will |
| 163 | likely be a comment about it. Please report any issue to the GitHub page! |
| 164 | - Try to keep your copy of dear imgui reasonably up to date. |
| 165 | |
| 166 | |
| 167 | GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE |
| 168 | --------------------------------------------------------------- |
| 169 | - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. |
| 170 | - In the majority of cases you should be able to use unmodified back-ends files available in the examples/ folder. |
| 171 | - Add the Dear ImGui source files + selected back-end source files to your projects or using your preferred build system. |
| 172 | It is recommended you build and statically link the .cpp files as part of your project and NOT as shared library (DLL). |
| 173 | - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types. |
| 174 | - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. |
| 175 | - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. |
| 176 | Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" |
| 177 | phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render(). |
| 178 | - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code. |
| 179 | - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. |
| 180 | |
| 181 | |
| 182 | HOW A SIMPLE APPLICATION MAY LOOK LIKE |
| 183 | -------------------------------------- |
| 184 | EXHIBIT 1: USING THE EXAMPLE BINDINGS (= imgui_impl_XXX.cpp files from the examples/ folder). |
| 185 | The sub-folders in examples/ contains examples applications following this structure. |
| 186 | |
| 187 | // Application init: create a dear imgui context, setup some options, load fonts |
| 188 | ImGui::CreateContext(); |
| 189 | ImGuiIO& io = ImGui::GetIO(); |
| 190 | // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. |
| 191 | // TODO: Fill optional fields of the io structure later. |
| 192 | // TODO: Load TTF/OTF fonts if you don't want to use the default font. |
| 193 | |
| 194 | // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp) |
| 195 | ImGui_ImplWin32_Init(hwnd); |
| 196 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); |
| 197 | |
| 198 | // Application main loop |
| 199 | while (true) |
| 200 | { |
| 201 | // Feed inputs to dear imgui, start new frame |
| 202 | ImGui_ImplDX11_NewFrame(); |
| 203 | ImGui_ImplWin32_NewFrame(); |
| 204 | ImGui::NewFrame(); |
| 205 | |
| 206 | // Any application code here |
| 207 | ImGui::Text("Hello, world!"); |
| 208 | |
| 209 | // Render dear imgui into screen |
| 210 | ImGui::Render(); |
| 211 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); |
| 212 | g_pSwapChain->Present(1, 0); |
| 213 | } |
| 214 | |
| 215 | // Shutdown |
| 216 | ImGui_ImplDX11_Shutdown(); |
| 217 | ImGui_ImplWin32_Shutdown(); |
| 218 | ImGui::DestroyContext(); |
| 219 | |
| 220 | EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE |
| 221 | |
| 222 | // Application init: create a dear imgui context, setup some options, load fonts |
| 223 | ImGui::CreateContext(); |
| 224 | ImGuiIO& io = ImGui::GetIO(); |
| 225 | // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. |
| 226 | // TODO: Fill optional fields of the io structure later. |
| 227 | // TODO: Load TTF/OTF fonts if you don't want to use the default font. |
| 228 | |
| 229 | // Build and load the texture atlas into a texture |
| 230 | // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) |
| 231 | int width, height; |
| 232 | unsigned char* pixels = NULL; |
| 233 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); |
| 234 | |
| 235 | // At this point you've got the texture data and you need to upload that your your graphic system: |
| 236 | // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. |
| 237 | // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. |
| 238 | MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) |
| 239 | io.Fonts->TexID = (void*)texture; |
| 240 | |
| 241 | // Application main loop |
| 242 | while (true) |
| 243 | { |
| 244 | // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. |
| 245 | // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings) |
| 246 | io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) |
| 247 | io.DisplaySize.x = 1920.0f; // set the current display width |
| 248 | io.DisplaySize.y = 1280.0f; // set the current display height here |
| 249 | io.MousePos = my_mouse_pos; // set the mouse position |
| 250 | io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states |
| 251 | io.MouseDown[1] = my_mouse_buttons[1]; |
| 252 | |
| 253 | // Call NewFrame(), after this point you can use ImGui::* functions anytime |
| 254 | // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere) |
| 255 | ImGui::NewFrame(); |
| 256 | |
| 257 | // Most of your application code here |
| 258 | ImGui::Text("Hello, world!"); |
| 259 | MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); |
| 260 | MyGameRender(); // may use any Dear ImGui functions as well! |
| 261 | |
| 262 | // Render dear imgui, swap buffers |
| 263 | // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code) |
| 264 | ImGui::EndFrame(); |
| 265 | ImGui::Render(); |
| 266 | ImDrawData* draw_data = ImGui::GetDrawData(); |
| 267 | MyImGuiRenderFunction(draw_data); |
| 268 | SwapBuffers(); |
| 269 | } |
| 270 | |
| 271 | // Shutdown |
| 272 | ImGui::DestroyContext(); |
| 273 | |
| 274 | To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest your application, |
| 275 | you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! |
| 276 | Please read the FAQ and example applications for details about this! |
| 277 | |
| 278 | |
| 279 | HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE |
| 280 | --------------------------------------------- |
| 281 | The bindings in impl_impl_XXX.cpp files contains many working implementations of a rendering function. |
| 282 | |
| 283 | void void MyImGuiRenderFunction(ImDrawData* draw_data) |
| 284 | { |
| 285 | // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled |
| 286 | // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize |
| 287 | // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize |
| 288 | // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. |
| 289 | for (int n = 0; n < draw_data->CmdListsCount; n++) |
| 290 | { |
| 291 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; |
| 292 | const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui |
| 293 | const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui |
| 294 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) |
| 295 | { |
| 296 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; |
| 297 | if (pcmd->UserCallback) |
| 298 | { |
| 299 | pcmd->UserCallback(cmd_list, pcmd); |
| 300 | } |
| 301 | else |
| 302 | { |
| 303 | // The texture for the draw call is specified by pcmd->TextureId. |
| 304 | // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. |
| 305 | MyEngineBindTexture((MyTexture*)pcmd->TextureId); |
| 306 | |
| 307 | // We are using scissoring to clip some objects. All low-level graphics API should supports it. |
| 308 | // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches |
| 309 | // (some elements visible outside their bounds) but you can fix that once everything else works! |
| 310 | // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize) |
| 311 | // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize. |
| 312 | // However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github), |
| 313 | // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. |
| 314 | // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) |
| 315 | ImVec2 pos = draw_data->DisplayPos; |
| 316 | MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y)); |
| 317 | |
| 318 | // Render 'pcmd->ElemCount/3' indexed triangles. |
| 319 | // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. |
| 320 | MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); |
| 321 | } |
| 322 | idx_buffer += pcmd->ElemCount; |
| 323 | } |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | |
| 328 | USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS |
| 329 | ------------------------------------------ |
| 330 | - The gamepad/keyboard navigation is fairly functional and keeps being improved. |
| 331 | - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse! |
| 332 | - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 |
| 333 | - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. |
| 334 | - Keyboard: |
| 335 | - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. |
| 336 | NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. |
| 337 | - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag |
| 338 | will be set. For more advanced uses, you may want to read from: |
| 339 | - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. |
| 340 | - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). |
| 341 | - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. |
| 342 | Please reach out if you think the game vs navigation input sharing could be improved. |
| 343 | - Gamepad: |
| 344 | - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. |
| 345 | - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). |
| 346 | Note that io.NavInputs[] is cleared by EndFrame(). |
| 347 | - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: |
| 348 | 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. |
| 349 | - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. |
| 350 | Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). |
| 351 | - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW. |
| 352 | - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo |
| 353 | to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. |
| 354 | - Mouse: |
| 355 | - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. |
| 356 | - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. |
| 357 | - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. |
| 358 | Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. |
| 359 | When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. |
| 360 | When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that. |
| 361 | (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!) |
| 362 | (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want |
| 363 | to set a boolean to ignore your other external mouse positions until the external source is moved again.) |
| 364 | |
| 365 | |
| 366 | API BREAKING CHANGES |
| 367 | ==================== |
| 368 | |
| 369 | Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. |
| 370 | Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. |
| 371 | When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. |
| 372 | You can read releases logs https://github.com/ocornut/imgui/releases for more details. |
| 373 | |
| 374 | - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed). |
| 375 | - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently). |
| 376 | - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton. |
| 377 | - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory. |
| 378 | - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result. |
| 379 | - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now! |
| 380 | - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar(). |
| 381 | replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). |
| 382 | worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions: |
| 383 | - if you omitted the 'power' parameter (likely!), you are not affected. |
| 384 | - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct. |
| 385 | - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. |
| 386 | see https://github.com/ocornut/imgui/issues/3361 for all details. |
| 387 | kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used. |
| 388 | for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. |
| 389 | - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime. |
| 390 | - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems. |
| 391 | - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79] |
| 392 | - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017. |
| 393 | - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular(). |
| 394 | - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more. |
| 395 | - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead. |
| 396 | - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value. |
| 397 | - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017): |
| 398 | - ShowTestWindow() -> use ShowDemoWindow() |
| 399 | - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow) |
| 400 | - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) |
| 401 | - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f) |
| 402 | - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing() |
| 403 | - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg |
| 404 | - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding |
| 405 | - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap |
| 406 | - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS |
| 407 | - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was the vaguely documented and rarely if ever used). Instead we added an explicit PrimUnreserve() API. |
| 408 | - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it). |
| 409 | - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert. |
| 410 | - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency. |
| 411 | - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency. |
| 412 | - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): |
| 413 | - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed |
| 414 | - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) |
| 415 | - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding() |
| 416 | - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f) |
| 417 | - ImFont::Glyph -> use ImFontGlyph |
| 418 | - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. |
| 419 | if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. |
| 420 | The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). |
| 421 | If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you. |
| 422 | - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete). |
| 423 | - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete). |
| 424 | - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71. |
| 425 | - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have |
| 426 | overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering. |
| 427 | This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows. |
| 428 | Please reach out if you are affected. |
| 429 | - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). |
| 430 | - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c). |
| 431 | - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. |
| 432 | - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). |
| 433 | - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). |
| 434 | - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). |
| 435 | - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrary small value! |
| 436 | - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). |
| 437 | - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! |
| 438 | - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). |
| 439 | - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects. |
| 440 | - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. |
| 441 | - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. |
| 442 | - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). |
| 443 | - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. |
| 444 | If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. |
| 445 | - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) |
| 446 | - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp. |
| 447 | NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED. |
| 448 | Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions. |
| 449 | - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent). |
| 450 | - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). |
| 451 | - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). |
| 452 | - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature. |
| 453 | - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. |
| 454 | - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. |
| 455 | - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). |
| 456 | - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). |
| 457 | old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports. |
| 458 | when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. |
| 459 | in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. |
| 460 | - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. |
| 461 | - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. |
| 462 | - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. |
| 463 | If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. |
| 464 | To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. |
| 465 | If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them. |
| 466 | - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", |
| 467 | consistent with other functions. Kept redirection functions (will obsolete). |
| 468 | - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. |
| 469 | - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). |
| 470 | - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. |
| 471 | - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. |
| 472 | - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. |
| 473 | - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment. |
| 474 | - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display. |
| 475 | - 2018/02/07 (1.60) - reorganized context handling to be more explicit, |
| 476 | - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. |
| 477 | - removed Shutdown() function, as DestroyContext() serve this purpose. |
| 478 | - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. |
| 479 | - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. |
| 480 | - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. |
| 481 | - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths. |
| 482 | - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). |
| 483 | - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). |
| 484 | - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. |
| 485 | - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side. |
| 486 | - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). |
| 487 | - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags |
| 488 | - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame. |
| 489 | - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. |
| 490 | - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). |
| 491 | - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). |
| 492 | - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). |
| 493 | - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). |
| 494 | - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). |
| 495 | - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed. |
| 496 | - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up. |
| 497 | Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions. |
| 498 | - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. |
| 499 | - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. |
| 500 | - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. |
| 501 | - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); |
| 502 | - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency. |
| 503 | - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. |
| 504 | - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details. |
| 505 | removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. |
| 506 | IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly) |
| 507 | IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow) |
| 508 | IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior] |
| 509 | - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! |
| 510 | - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). |
| 511 | - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). |
| 512 | - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). |
| 513 | - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". |
| 514 | - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! |
| 515 | - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). |
| 516 | - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). |
| 517 | - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. |
| 518 | - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. |
| 519 | - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type. |
| 520 | - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. |
| 521 | - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete). |
| 522 | - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete). |
| 523 | - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). |
| 524 | - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. |
| 525 | - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. |
| 526 | - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))' |
| 527 | - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse |
| 528 | - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. |
| 529 | - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. |
| 530 | - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). |
| 531 | - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. |
| 532 | - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. |
| 533 | - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. |
| 534 | - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. |
| 535 | If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. |
| 536 | This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color: |
| 537 | ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } |
| 538 | If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. |
| 539 | - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). |
| 540 | - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. |
| 541 | - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). |
| 542 | - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. |
| 543 | - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). |
| 544 | - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) |
| 545 | - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). |
| 546 | - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. |
| 547 | - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. |
| 548 | - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. |
| 549 | - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. |
| 550 | - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. |
| 551 | GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side. |
| 552 | GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out! |
| 553 | - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize |
| 554 | - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project. |
| 555 | - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason |
| 556 | - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. |
| 557 | you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. |
| 558 | - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. |
| 559 | this necessary change will break your rendering function! the fix should be very easy. sorry for that :( |
| 560 | - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. |
| 561 | - the signature of the io.RenderDrawListsFn handler has changed! |
| 562 | old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) |
| 563 | new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). |
| 564 | parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' |
| 565 | ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. |
| 566 | ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. |
| 567 | - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. |
| 568 | - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering! |
| 569 | - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! |
| 570 | - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. |
| 571 | - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). |
| 572 | - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. |
| 573 | - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence |
| 574 | - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry! |
| 575 | - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). |
| 576 | - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). |
| 577 | - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. |
| 578 | - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. |
| 579 | - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). |
| 580 | - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. |
| 581 | - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API |
| 582 | - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. |
| 583 | - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. |
| 584 | - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. |
| 585 | - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing |
| 586 | - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. |
| 587 | - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) |
| 588 | - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. |
| 589 | - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. |
| 590 | - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. |
| 591 | - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior |
| 592 | - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() |
| 593 | - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) |
| 594 | - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. |
| 595 | - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. |
| 596 | - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. |
| 597 | - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; |
| 598 | - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier; |
| 599 | you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. |
| 600 | - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. |
| 601 | - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) |
| 602 | - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets |
| 603 | - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) |
| 604 | - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) |
| 605 | - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility |
| 606 | - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() |
| 607 | - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly) |
| 608 | - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) |
| 609 | - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() |
| 610 | - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn |
| 611 | - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) |
| 612 | - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite |
| 613 | - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes |
| 614 | |
| 615 | |
| 616 | FREQUENTLY ASKED QUESTIONS (FAQ) |
| 617 | ================================ |
| 618 | |
| 619 | Read all answers online: |
| 620 | https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url) |
| 621 | Read all answers locally (with a text editor or ideally a Markdown viewer): |
| 622 | docs/FAQ.md |
| 623 | Some answers are copied down here to facilitate searching in code. |
| 624 | |
| 625 | Q&A: Basics |
| 626 | =========== |
| 627 | |
| 628 | Q: Where is the documentation? |
| 629 | A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++. |
| 630 | - Run the examples/ and explore them. |
| 631 | - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. |
| 632 | - The demo covers most features of Dear ImGui, so you can read the code and see its output. |
| 633 | - See documentation and comments at the top of imgui.cpp + effectively imgui.h. |
| 634 | - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the |
| 635 | examples/ folder to explain how to integrate Dear ImGui with your own engine/application. |
| 636 | - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. |
| 637 | - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. |
| 638 | - Your programming IDE is your friend, find the type or function declaration to find comments |
| 639 | associated to it. |
| 640 | |
| 641 | Q: What is this library called? |
| 642 | Q: Which version should I get? |
| 643 | >> This library is called "Dear ImGui", please don't call it "ImGui" :) |
| 644 | >> See https://www.dearimgui.org/faq for details. |
| 645 | |
| 646 | Q&A: Integration |
| 647 | ================ |
| 648 | |
| 649 | Q: How to get started? |
| 650 | A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. |
| 651 | |
| 652 | Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application? |
| 653 | A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! |
| 654 | >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this. |
| 655 | |
| 656 | Q. How can I enable keyboard controls? |
| 657 | Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) |
| 658 | Q: I integrated Dear ImGui in my engine and little squares are showing instead of text.. |
| 659 | Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. |
| 660 | Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries.. |
| 661 | >> See https://www.dearimgui.org/faq |
| 662 | |
| 663 | Q&A: Usage |
| 664 | ---------- |
| 665 | |
| 666 | Q: Why is my widget not reacting when I click on it? |
| 667 | Q: How can I have widgets with an empty label? |
| 668 | Q: How can I have multiple widgets with the same label? |
| 669 | Q: How can I display an image? What is ImTextureID, how does it works? |
| 670 | Q: How can I use my own math types instead of ImVec2/ImVec4? |
| 671 | Q: How can I interact with standard C++ types (such as std::string and std::vector)? |
| 672 | Q: How can I display custom shapes? (using low-level ImDrawList API) |
| 673 | >> See https://www.dearimgui.org/faq |
| 674 | |
| 675 | Q&A: Fonts, Text |
| 676 | ================ |
| 677 | |
| 678 | Q: How should I handle DPI in my application? |
| 679 | Q: How can I load a different font than the default? |
| 680 | Q: How can I easily use icons in my application? |
| 681 | Q: How can I load multiple fonts? |
| 682 | Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? |
| 683 | >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md |
| 684 | |
| 685 | Q&A: Concerns |
| 686 | ============= |
| 687 | |
| 688 | Q: Who uses Dear ImGui? |
| 689 | Q: Can you create elaborate/serious tools with Dear ImGui? |
| 690 | Q: Can you reskin the look of Dear ImGui? |
| 691 | Q: Why using C++ (as opposed to C)? |
| 692 | >> See https://www.dearimgui.org/faq |
| 693 | |
| 694 | Q&A: Community |
| 695 | ============== |
| 696 | |
| 697 | Q: How can I help? |
| 698 | A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui! |
| 699 | We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. |
| 700 | This is among the most useful thing you can do for Dear ImGui. With increased funding we can hire more people working on this project. |
| 701 | - Individuals: you can support continued development via PayPal donations. See README. |
| 702 | - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt |
| 703 | and see how you want to help and can help! |
| 704 | - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. |
| 705 | You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3488). Visuals are ideal as they inspire other programmers. |
| 706 | But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions. |
| 707 | - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately). |
| 708 | |
| 709 | */ |
| 710 | |
| 711 | //------------------------------------------------------------------------- |
| 712 | // [SECTION] INCLUDES |
| 713 | //------------------------------------------------------------------------- |
| 2310 | ImGuiStyle& ImGui::GetStyle() |
| 2311 | { |
| 2312 | IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); |
| 2313 | return GImGui->Style; |
| 2314 | } |
| 2315 | |
| 2316 | ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) |
| 2317 | { |
| 2318 | ImGuiStyle& style = GImGui->Style; |
| 2319 | ImVec4 c = style.Colors[idx]; |
| 2320 | c.w *= style.Alpha * alpha_mul; |
| 2321 | return ColorConvertFloat4ToU32(c); |
| 2322 | } |
| 2323 | |
| 2324 | ImU32 ImGui::GetColorU32(const ImVec4& col) |
| 2325 | { |
| 2326 | ImGuiStyle& style = GImGui->Style; |
| 2327 | ImVec4 c = col; |
| 2328 | c.w *= style.Alpha; |
| 2329 | return ColorConvertFloat4ToU32(c); |
| 2330 | } |
| 2331 | |
| 2332 | const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) |
| 2333 | { |
| 2334 | ImGuiStyle& style = GImGui->Style; |
| 2335 | return style.Colors[idx]; |
| 2336 | } |
| 2337 | |
| 2338 | ImU32 ImGui::GetColorU32(ImU32 col) |
| 2339 | { |
| 2340 | ImGuiStyle& style = GImGui->Style; |
| 2341 | if (style.Alpha >= 1.0f) |
| 2342 | return col; |
| 2343 | ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; |
| 2344 | a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. |
| 2345 | return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); |
| 2346 | } |
| 2347 | |
| 2348 | // FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32 |
| 2349 | void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) |
| 2350 | { |
| 2351 | ImGuiContext& g = *GImGui; |
| 2352 | ImGuiColorMod backup; |
| 2353 | backup.Col = idx; |
| 2354 | backup.BackupValue = g.Style.Colors[idx]; |
| 2355 | g.ColorModifiers.push_back(backup); |
| 2356 | g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); |
| 2357 | } |
| 2358 | |
| 2359 | void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) |
| 2360 | { |
| 2361 | ImGuiContext& g = *GImGui; |
| 2362 | ImGuiColorMod backup; |
| 2363 | backup.Col = idx; |
| 2364 | backup.BackupValue = g.Style.Colors[idx]; |
| 2365 | g.ColorModifiers.push_back(backup); |
| 2366 | g.Style.Colors[idx] = col; |
| 2367 | } |
| 2368 | |
| 2369 | void ImGui::PopStyleColor(int count) |
| 2370 | { |
| 2371 | ImGuiContext& g = *GImGui; |
| 2372 | while (count > 0) |
| 2373 | { |
| 2374 | ImGuiColorMod& backup = g.ColorModifiers.back(); |
| 2375 | g.Style.Colors[backup.Col] = backup.BackupValue; |
| 2376 | g.ColorModifiers.pop_back(); |
| 2377 | count--; |
| 2378 | } |
| 2379 | } |
| 2380 | |
| 2381 | struct ImGuiStyleVarInfo |
| 2382 | { |
| 2383 | ImGuiDataType Type; |
| 2384 | ImU32 Count; |
| 2385 | ImU32 Offset; |
| 2386 | void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); } |
| 2387 | }; |
| 2388 | |
| 2389 | static const ImGuiStyleVarInfo GStyleVarInfo[] = |
| 2390 | { |
| 2391 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha |
| 2392 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding |
| 2393 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding |
| 2394 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize |
| 2395 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize |
| 2396 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign |
| 2397 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding |
| 2398 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize |
| 2399 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding |
| 2400 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize |
| 2401 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding |
| 2402 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding |
| 2403 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize |
| 2404 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing |
| 2405 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing |
| 2406 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing |
| 2407 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize |
| 2408 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding |
| 2409 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize |
| 2410 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding |
| 2411 | { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding |
| 2412 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign |
| 2413 | { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign |
| 2414 | }; |
| 2415 | |
| 2416 | static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) |
| 2417 | { |
| 2418 | IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); |
| 2419 | IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); |
| 2420 | return &GStyleVarInfo[idx]; |
| 2421 | } |
| 2422 | |
| 2423 | void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) |
| 2424 | { |
| 2425 | const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); |
| 2426 | if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) |
| 2427 | { |
| 2428 | ImGuiContext& g = *GImGui; |
| 2429 | float* pvar = (float*)var_info->GetVarPtr(&g.Style); |
| 2430 | g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); |
| 2431 | *pvar = val; |
| 2432 | return; |
| 2433 | } |
| 2434 | IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); |
| 2435 | } |
| 2436 | |
| 2437 | void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) |
| 2438 | { |
| 2439 | const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); |
| 2440 | if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) |
| 2441 | { |
| 2442 | ImGuiContext& g = *GImGui; |
| 2443 | ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); |
| 2444 | g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); |
| 2445 | *pvar = val; |
| 2446 | return; |
| 2447 | } |
| 2448 | IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); |
| 2449 | } |
| 2450 | |
| 2451 | void ImGui::PopStyleVar(int count) |
| 2452 | { |
| 2453 | ImGuiContext& g = *GImGui; |
| 2454 | while (count > 0) |
| 2455 | { |
| 2456 | // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. |
| 2457 | ImGuiStyleMod& backup = g.StyleModifiers.back(); |
| 2458 | const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); |
| 2459 | void* data = info->GetVarPtr(&g.Style); |
| 2460 | if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } |
| 2461 | else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } |
| 2462 | g.StyleModifiers.pop_back(); |
| 2463 | count--; |
| 2464 | } |
| 2465 | } |
| 2466 | |
| 2467 | const char* ImGui::GetStyleColorName(ImGuiCol idx) |
| 2468 | { |
| 2469 | // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; |
| 2470 | switch (idx) |
| 2471 | { |
| 2472 | case ImGuiCol_Text: return "Text"; |
| 2473 | case ImGuiCol_TextDisabled: return "TextDisabled"; |
| 2474 | case ImGuiCol_WindowBg: return "WindowBg"; |
| 2475 | case ImGuiCol_ChildBg: return "ChildBg"; |
| 2476 | case ImGuiCol_PopupBg: return "PopupBg"; |
| 2477 | case ImGuiCol_Border: return "Border"; |
| 2478 | case ImGuiCol_BorderShadow: return "BorderShadow"; |
| 2479 | case ImGuiCol_FrameBg: return "FrameBg"; |
| 2480 | case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; |
| 2481 | case ImGuiCol_FrameBgActive: return "FrameBgActive"; |
| 2482 | case ImGuiCol_TitleBg: return "TitleBg"; |
| 2483 | case ImGuiCol_TitleBgActive: return "TitleBgActive"; |
| 2484 | case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; |
| 2485 | case ImGuiCol_MenuBarBg: return "MenuBarBg"; |
| 2486 | case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; |
| 2487 | case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; |
| 2488 | case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; |
| 2489 | case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; |
| 2490 | case ImGuiCol_CheckMark: return "CheckMark"; |
| 2491 | case ImGuiCol_SliderGrab: return "SliderGrab"; |
| 2492 | case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; |
| 2493 | case ImGuiCol_Button: return "Button"; |
| 2494 | case ImGuiCol_ButtonHovered: return "ButtonHovered"; |
| 2495 | case ImGuiCol_ButtonActive: return "ButtonActive"; |
| 2496 | case ImGuiCol_Header: return "Header"; |
| 2497 | case ImGuiCol_HeaderHovered: return "HeaderHovered"; |
| 2498 | case ImGuiCol_HeaderActive: return "HeaderActive"; |
| 2499 | case ImGuiCol_Separator: return "Separator"; |
| 2500 | case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; |
| 2501 | case ImGuiCol_SeparatorActive: return "SeparatorActive"; |
| 2502 | case ImGuiCol_ResizeGrip: return "ResizeGrip"; |
| 2503 | case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; |
| 2504 | case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; |
| 2505 | case ImGuiCol_Tab: return "Tab"; |
| 2506 | case ImGuiCol_TabHovered: return "TabHovered"; |
| 2507 | case ImGuiCol_TabActive: return "TabActive"; |
| 2508 | case ImGuiCol_TabUnfocused: return "TabUnfocused"; |
| 2509 | case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; |
| 2510 | case ImGuiCol_PlotLines: return "PlotLines"; |
| 2511 | case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; |
| 2512 | case ImGuiCol_PlotHistogram: return "PlotHistogram"; |
| 2513 | case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; |
| 2514 | case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; |
| 2515 | case ImGuiCol_DragDropTarget: return "DragDropTarget"; |
| 2516 | case ImGuiCol_NavHighlight: return "NavHighlight"; |
| 2517 | case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; |
| 2518 | case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; |
| 2519 | case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; |
| 2520 | } |
| 2521 | IM_ASSERT(0); |
| 2522 | return "Unknown"; |
| 2523 | } |
| 2524 | |
| 2525 | |
| 2526 | //----------------------------------------------------------------------------- |
| 2527 | // [SECTION] RENDER HELPERS |
| 2528 | // Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, |
| 2529 | // we need a nicer separation between low-level functions and high-level functions relying on the ImGui context. |
| 2530 | // Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context. |
| 2531 | //----------------------------------------------------------------------------- |
| 2532 | |
| 2533 | const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) |
| 2534 | { |
| 2535 | const char* text_display_end = text; |
| 2536 | if (!text_end) |
| 2537 | text_end = (const char*)-1; |
| 2538 | |
| 2539 | while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) |
| 2540 | text_display_end++; |
| 2541 | return text_display_end; |
| 2542 | } |
| 2543 | |
| 2544 | // Internal ImGui functions to render text |
| 2545 | // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() |
| 2546 | void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) |
| 2547 | { |
| 2548 | ImGuiContext& g = *GImGui; |
| 2549 | ImGuiWindow* window = g.CurrentWindow; |
| 2550 | |
| 2551 | // Hide anything after a '##' string |
| 2552 | const char* text_display_end; |
| 2553 | if (hide_text_after_hash) |
| 2554 | { |
| 2555 | text_display_end = FindRenderedTextEnd(text, text_end); |
| 2556 | } |
| 2557 | else |
| 2558 | { |
| 2559 | if (!text_end) |
| 2560 | text_end = text + strlen(text); // FIXME-OPT |
| 2561 | text_display_end = text_end; |
| 2562 | } |
| 2563 | |
| 2564 | if (text != text_display_end) |
| 2565 | { |
| 2566 | window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); |
| 2567 | if (g.LogEnabled) |
| 2568 | LogRenderedText(&pos, text, text_display_end); |
| 2569 | } |
| 2570 | } |
| 2571 | |
| 2572 | void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) |
| 2573 | { |
| 2574 | ImGuiContext& g = *GImGui; |
| 2575 | ImGuiWindow* window = g.CurrentWindow; |
| 2576 | |
| 2577 | if (!text_end) |
| 2578 | text_end = text + strlen(text); // FIXME-OPT |
| 2579 | |
| 2580 | if (text != text_end) |
| 2581 | { |
| 2582 | window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); |
| 2583 | if (g.LogEnabled) |
| 2584 | LogRenderedText(&pos, text, text_end); |
| 2585 | } |
| 2586 | } |
| 2587 | |
| 2588 | // Default clip_rect uses (pos_min,pos_max) |
| 2589 | // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) |
| 2590 | void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) |
| 2591 | { |
| 2592 | // Perform CPU side clipping for single clipped element to avoid using scissor state |
| 2593 | ImVec2 pos = pos_min; |
| 2594 | const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); |
| 2595 | |
| 2596 | const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; |
| 2597 | const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; |
| 2598 | bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); |
| 2599 | if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min |
| 2600 | need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); |
| 2601 | |
| 2602 | // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. |
| 2603 | if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); |
| 2604 | if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); |
| 2605 | |
| 2606 | // Render |
| 2607 | if (need_clipping) |
| 2608 | { |
| 2609 | ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); |
| 2610 | draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); |
| 2611 | } |
| 2612 | else |
| 2613 | { |
| 2614 | draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); |
| 2615 | } |
| 2616 | } |
| 2617 | |
| 2618 | void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) |
| 2619 | { |
| 2620 | // Hide anything after a '##' string |
| 2621 | const char* text_display_end = FindRenderedTextEnd(text, text_end); |
| 2622 | const int text_len = (int)(text_display_end - text); |
| 2623 | if (text_len == 0) |
| 2624 | return; |
| 2625 | |
| 2626 | ImGuiContext& g = *GImGui; |
| 2627 | ImGuiWindow* window = g.CurrentWindow; |
| 2628 | RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); |
| 2629 | if (g.LogEnabled) |
| 2630 | LogRenderedText(&pos_min, text, text_display_end); |
| 2631 | } |
| 2632 | |
| 2633 | |
| 2634 | // Another overly complex function until we reorganize everything into a nice all-in-one helper. |
| 2635 | // This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. |
| 2636 | // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. |
| 2637 | void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) |
| 2638 | { |
| 2639 | ImGuiContext& g = *GImGui; |
| 2640 | if (text_end_full == NULL) |
| 2641 | text_end_full = FindRenderedTextEnd(text); |
| 2642 | const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); |
| 2643 | |
| 2644 | //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); |
| 2645 | //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); |
| 2646 | //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); |
| 2647 | // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. |
| 2648 | if (text_size.x > pos_max.x - pos_min.x) |
| 2649 | { |
| 2650 | // Hello wo... |
| 2651 | // | | | |
| 2652 | // min max ellipsis_max |
| 2653 | // <-> this is generally some padding value |
| 2654 | |
| 2655 | const ImFont* font = draw_list->_Data->Font; |
| 2656 | const float font_size = draw_list->_Data->FontSize; |
| 2657 | const char* text_end_ellipsis = NULL; |
| 2658 | |
| 2659 | ImWchar ellipsis_char = font->EllipsisChar; |
| 2660 | int ellipsis_char_count = 1; |
| 2661 | if (ellipsis_char == (ImWchar)-1) |
| 2662 | { |
| 2663 | ellipsis_char = (ImWchar)'.'; |
| 2664 | ellipsis_char_count = 3; |
| 2665 | } |
| 2666 | const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); |
| 2667 | |
| 2668 | float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side |
| 2669 | float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis |
| 2670 | |
| 2671 | if (ellipsis_char_count > 1) |
| 2672 | { |
| 2673 | // Full ellipsis size without free spacing after it. |
| 2674 | const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize); |
| 2675 | ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots; |
| 2676 | ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; |
| 2677 | } |
| 2678 | |
| 2679 | // We can now claim the space between pos_max.x and ellipsis_max.x |
| 2680 | const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); |
| 2681 | float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; |
| 2682 | if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) |
| 2683 | { |
| 2684 | // Always display at least 1 character if there's no room for character + ellipsis |
| 2685 | text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); |
| 2686 | text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; |
| 2687 | } |
| 2688 | while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) |
| 2689 | { |
| 2690 | // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) |
| 2691 | text_end_ellipsis--; |
| 2692 | text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte |
| 2693 | } |
| 2694 | |
| 2695 | // Render text, render ellipsis |
| 2696 | RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); |
| 2697 | float ellipsis_x = pos_min.x + text_size_clipped_x; |
| 2698 | if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) |
| 2699 | for (int i = 0; i < ellipsis_char_count; i++) |
| 2700 | { |
| 2701 | font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); |
| 2702 | ellipsis_x += ellipsis_glyph_width; |
| 2703 | } |
| 2704 | } |
| 2705 | else |
| 2706 | { |
| 2707 | RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); |
| 2708 | } |
| 2709 | |
| 2710 | if (g.LogEnabled) |
| 2711 | LogRenderedText(&pos_min, text, text_end_full); |
| 2712 | } |
| 2713 | |
| 2714 | // Render a rectangle shaped with optional rounding and borders |
| 2715 | void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) |
| 2716 | { |
| 2717 | ImGuiContext& g = *GImGui; |
| 2718 | ImGuiWindow* window = g.CurrentWindow; |
| 2719 | window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); |
| 2720 | const float border_size = g.Style.FrameBorderSize; |
| 2721 | if (border && border_size > 0.0f) |
| 2722 | { |
| 2723 | window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); |
| 2724 | window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); |
| 2725 | } |
| 2726 | } |
| 2727 | |
| 2728 | void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) |
| 2729 | { |
| 2730 | ImGuiContext& g = *GImGui; |
| 2731 | ImGuiWindow* window = g.CurrentWindow; |
| 2732 | const float border_size = g.Style.FrameBorderSize; |
| 2733 | if (border_size > 0.0f) |
| 2734 | { |
| 2735 | window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size); |
| 2736 | window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size); |
| 2737 | } |
| 2738 | } |
| 2739 | |
| 2740 | void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) |
| 2741 | { |
| 2742 | ImGuiContext& g = *GImGui; |
| 2743 | if (id != g.NavId) |
| 2744 | return; |
| 2745 | if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) |
| 2746 | return; |
| 2747 | ImGuiWindow* window = g.CurrentWindow; |
| 2748 | if (window->DC.NavHideHighlightOneFrame) |
| 2749 | return; |
| 2750 | |
| 2751 | float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; |
| 2752 | ImRect display_rect = bb; |
| 2753 | display_rect.ClipWith(window->ClipRect); |
| 2754 | if (flags & ImGuiNavHighlightFlags_TypeDefault) |
| 2755 | { |
| 2756 | const float THICKNESS = 2.0f; |
| 2757 | const float DISTANCE = 3.0f + THICKNESS * 0.5f; |
| 2758 | display_rect.Expand(ImVec2(DISTANCE, DISTANCE)); |
| 2759 | bool fully_visible = window->ClipRect.Contains(display_rect); |
| 2760 | if (!fully_visible) |
| 2761 | window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); |
| 2762 | window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS); |
| 2763 | if (!fully_visible) |
| 2764 | window->DrawList->PopClipRect(); |
| 2765 | } |
| 2766 | if (flags & ImGuiNavHighlightFlags_TypeThin) |
| 2767 | { |
| 2768 | window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f); |
| 2769 | } |
| 2770 | } |
| 2771 | |
| 2772 | //----------------------------------------------------------------------------- |
| 2773 | // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) |
| 2774 | //----------------------------------------------------------------------------- |
| 2775 | |
| 2776 | // ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods |
2128 | | // An active popup disable hovering on other windows (apart from its own children) |
2129 | | // FIXME-OPT: This could be cached/stored within the window. |
2130 | | ImGuiContext& g = *GImGui; |
2131 | | if (g.NavWindow) |
2132 | | if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) |
2133 | | if (focused_root_window->WasActive && focused_root_window != window->RootWindow) |
2134 | | { |
2135 | | // For the purpose of those flags we differentiate "standard popup" from "modal popup" |
2136 | | // NB: The order of those two tests is important because Modal windows are also Popups. |
2137 | | if (focused_root_window->Flags & ImGuiWindowFlags_Modal) |
2138 | | return false; |
2139 | | if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) |
2140 | | return false; |
2141 | | } |
2142 | | |
2143 | | return true; |
2144 | | } |
2145 | | |
2146 | | // Advance cursor given item size for layout. |
2147 | | void ImGui::ItemSize(const ImVec2& size, float text_offset_y) |
2148 | | { |
2149 | | ImGuiContext& g = *GImGui; |
2150 | | ImGuiWindow* window = g.CurrentWindow; |
2151 | | if (window->SkipItems) |
2152 | | return; |
2153 | | |
2154 | | // Always align ourselves on pixel boundaries |
2155 | | const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); |
2156 | | const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); |
2157 | | //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] |
2158 | | window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); |
2159 | | window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y)); |
2160 | | window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); |
2161 | | window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); |
2162 | | //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] |
2163 | | |
2164 | | window->DC.PrevLineHeight = line_height; |
2165 | | window->DC.PrevLineTextBaseOffset = text_base_offset; |
2166 | | window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f; |
2167 | | |
2168 | | // Horizontal layout mode |
2169 | | if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) |
2170 | | SameLine(); |
2171 | | } |
2172 | | |
2173 | | void ImGui::ItemSize(const ImRect& bb, float text_offset_y) |
2174 | | { |
2175 | | ItemSize(bb.GetSize(), text_offset_y); |
2176 | | } |
2177 | | |
2178 | | static ImGuiDir NavScoreItemGetQuadrant(float dx, float dy) |
2179 | | { |
2180 | | if (fabsf(dx) > fabsf(dy)) |
2181 | | return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; |
2182 | | return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; |
2183 | | } |
2184 | | |
2185 | | static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1) |
2186 | | { |
2187 | | if (a1 < b0) |
2188 | | return a1 - b0; |
2189 | | if (b1 < a0) |
2190 | | return a0 - b1; |
2191 | | return 0.0f; |
2192 | | } |
2193 | | |
2194 | | // Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057 |
2195 | | static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) |
2196 | | { |
2197 | | ImGuiContext& g = *GImGui; |
2198 | | ImGuiWindow* window = g.CurrentWindow; |
2199 | | if (g.NavLayer != window->DC.NavLayerCurrent) |
2200 | | return false; |
2201 | | |
2202 | | const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) |
2203 | | g.NavScoringCount++; |
2204 | | |
2205 | | // We perform scoring on items bounding box clipped by their parent window on the other axis (clipping on our movement axis would give us equal scores for all clipped items) |
2206 | | if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) |
2207 | | { |
2208 | | cand.Min.y = ImClamp(cand.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y); |
2209 | | cand.Max.y = ImClamp(cand.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y); |
2210 | | } |
2211 | | else |
2212 | | { |
2213 | | cand.Min.x = ImClamp(cand.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x); |
2214 | | cand.Max.x = ImClamp(cand.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x); |
2215 | | } |
2216 | | |
2217 | | // Compute distance between boxes |
2218 | | // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. |
2219 | | float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); |
2220 | | float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items |
2221 | | if (dby != 0.0f && dbx != 0.0f) |
2222 | | dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); |
2223 | | float dist_box = fabsf(dbx) + fabsf(dby); |
2224 | | |
2225 | | // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) |
2226 | | float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); |
2227 | | float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); |
2228 | | float dist_center = fabsf(dcx) + fabsf(dcy); // L1 metric (need this for our connectedness guarantee) |
2229 | | |
2230 | | // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance |
2231 | | ImGuiDir quadrant; |
2232 | | float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; |
2233 | | if (dbx != 0.0f || dby != 0.0f) |
2234 | | { |
2235 | | // For non-overlapping boxes, use distance between boxes |
2236 | | dax = dbx; |
2237 | | day = dby; |
2238 | | dist_axial = dist_box; |
2239 | | quadrant = NavScoreItemGetQuadrant(dbx, dby); |
2240 | | } |
2241 | | else if (dcx != 0.0f || dcy != 0.0f) |
2242 | | { |
2243 | | // For overlapping boxes with different centers, use distance between centers |
2244 | | dax = dcx; |
2245 | | day = dcy; |
2246 | | dist_axial = dist_center; |
2247 | | quadrant = NavScoreItemGetQuadrant(dcx, dcy); |
2248 | | } |
2249 | | else |
2250 | | { |
2251 | | // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) |
2252 | | quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; |
2253 | | } |
2254 | | |
2255 | | #if IMGUI_DEBUG_NAV_SCORING |
2256 | | char buf[128]; |
2257 | | if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max)) |
2258 | | { |
2259 | | ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); |
2260 | | ImDrawList* draw_list = ImGui::GetOverlayDrawList(); |
2261 | | draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100)); |
2262 | | draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200)); |
2263 | | draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + ImGui::CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 150)); |
2264 | | draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf); |
2265 | | } |
2266 | | else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate. |
2267 | | { |
2268 | | if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; } |
2269 | | if (quadrant == g.NavMoveDir) |
2270 | | { |
2271 | | ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); |
2272 | | ImDrawList* draw_list = ImGui::GetOverlayDrawList(); |
2273 | | draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200)); |
2274 | | draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf); |
2275 | | } |
2276 | | } |
2277 | | #endif |
2278 | | |
2279 | | // Is it in the quadrant we're interesting in moving to? |
2280 | | bool new_best = false; |
2281 | | if (quadrant == g.NavMoveDir) |
2282 | | { |
2283 | | // Does it beat the current best candidate? |
2284 | | if (dist_box < result->DistBox) |
2285 | | { |
2286 | | result->DistBox = dist_box; |
2287 | | result->DistCenter = dist_center; |
2288 | | return true; |
2289 | | } |
2290 | | if (dist_box == result->DistBox) |
2291 | | { |
2292 | | // Try using distance between center points to break ties |
2293 | | if (dist_center < result->DistCenter) |
2294 | | { |
2295 | | result->DistCenter = dist_center; |
2296 | | new_best = true; |
2297 | | } |
2298 | | else if (dist_center == result->DistCenter) |
2299 | | { |
2300 | | // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items |
2301 | | // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), |
2302 | | // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. |
2303 | | if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance |
2304 | | new_best = true; |
2305 | | } |
2306 | | } |
2307 | | } |
2308 | | |
2309 | | // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches |
2310 | | // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) |
2311 | | // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. |
2312 | | // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. |
2313 | | // Disabling it may however lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? |
2314 | | if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match |
2315 | | if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) |
2316 | | if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) |
2317 | | { |
2318 | | result->DistAxial = dist_axial; |
2319 | | new_best = true; |
2320 | | } |
2321 | | |
2322 | | return new_best; |
2323 | | } |
2324 | | |
2325 | | static void NavSaveLastChildNavWindow(ImGuiWindow* child_window) |
2326 | | { |
2327 | | ImGuiWindow* parent_window = child_window; |
2328 | | while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) |
2329 | | parent_window = parent_window->ParentWindow; |
2330 | | if (parent_window && parent_window != child_window) |
2331 | | parent_window->NavLastChildNavWindow = child_window; |
2332 | | } |
2333 | | |
2334 | | // Call when we are expected to land on Layer 0 after FocusWindow() |
2335 | | static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window) |
2336 | | { |
2337 | | return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window; |
2338 | | } |
2339 | | |
2340 | | static void NavRestoreLayer(int layer) |
2341 | | { |
2342 | | ImGuiContext& g = *GImGui; |
2343 | | g.NavLayer = layer; |
2344 | | if (layer == 0) |
2345 | | g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); |
2346 | | if (layer == 0 && g.NavWindow->NavLastIds[0] != 0) |
2347 | | SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]); |
2348 | | else |
2349 | | ImGui::NavInitWindow(g.NavWindow, true); |
2350 | | } |
2351 | | |
2352 | | static inline void NavUpdateAnyRequestFlag() |
2353 | | { |
2354 | | ImGuiContext& g = *GImGui; |
2355 | | g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); |
2356 | | if (g.NavAnyRequest) |
2357 | | IM_ASSERT(g.NavWindow != NULL); |
2358 | | } |
2359 | | |
2360 | | static bool NavMoveRequestButNoResultYet() |
2361 | | { |
2362 | | ImGuiContext& g = *GImGui; |
2363 | | return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; |
2364 | | } |
2365 | | |
2366 | | void ImGui::NavMoveRequestCancel() |
2367 | | { |
2368 | | ImGuiContext& g = *GImGui; |
2369 | | g.NavMoveRequest = false; |
2370 | | NavUpdateAnyRequestFlag(); |
2371 | | } |
2372 | | |
2373 | | // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) |
2374 | | static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) |
2375 | | { |
2376 | | ImGuiContext& g = *GImGui; |
2377 | | //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag. |
2378 | | // return; |
2379 | | |
2380 | | const ImGuiItemFlags item_flags = window->DC.ItemFlags; |
2381 | | const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos); |
2382 | | if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent) |
2383 | | { |
2384 | | // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback |
2385 | | if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0) |
2386 | | { |
2387 | | g.NavInitResultId = id; |
2388 | | g.NavInitResultRectRel = nav_bb_rel; |
2389 | | } |
2390 | | if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus)) |
2391 | | { |
2392 | | g.NavInitRequest = false; // Found a match, clear request |
2393 | | NavUpdateAnyRequestFlag(); |
2394 | | } |
2395 | | } |
2396 | | |
2397 | | // Scoring for navigation |
2398 | | if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav)) |
2399 | | { |
2400 | | ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; |
2401 | | #if IMGUI_DEBUG_NAV_SCORING |
2402 | | // [DEBUG] Score all items in NavWindow at all times |
2403 | | if (!g.NavMoveRequest) |
2404 | | g.NavMoveDir = g.NavMoveDirLast; |
2405 | | bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; |
2406 | | #else |
2407 | | bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); |
2408 | | #endif |
2409 | | if (new_best) |
2410 | | { |
2411 | | result->ID = id; |
2412 | | result->ParentID = window->IDStack.back(); |
2413 | | result->Window = window; |
2414 | | result->RectRel = nav_bb_rel; |
2415 | | } |
2416 | | } |
2417 | | |
2418 | | // Update window-relative bounding box of navigated item |
2419 | | if (g.NavId == id) |
2420 | | { |
2421 | | g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window. |
2422 | | g.NavLayer = window->DC.NavLayerCurrent; |
2423 | | g.NavIdIsAlive = true; |
2424 | | g.NavIdTabCounter = window->FocusIdxTabCounter; |
2425 | | window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position) |
2426 | | } |
2427 | | } |
2428 | | |
2429 | | // Declare item bounding box for clipping and interaction. |
2430 | | // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface |
2431 | | // declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd(). |
2432 | | bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) |
2433 | | { |
2434 | | ImGuiContext& g = *GImGui; |
2435 | | ImGuiWindow* window = g.CurrentWindow; |
2436 | | |
2437 | | if (id != 0) |
2438 | | { |
2439 | | // Navigation processing runs prior to clipping early-out |
2440 | | // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget |
2441 | | // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window. |
2442 | | // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. |
2443 | | // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick) |
2444 | | window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask; |
2445 | | if (g.NavId == id || g.NavAnyRequest) |
2446 | | if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) |
2447 | | if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) |
2448 | | NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id); |
2449 | | } |
2450 | | |
2451 | | window->DC.LastItemId = id; |
2452 | | window->DC.LastItemRect = bb; |
2453 | | window->DC.LastItemStatusFlags = 0; |
2454 | | |
2455 | | // Clipping test |
2456 | | const bool is_clipped = IsClippedEx(bb, id, false); |
2457 | | if (is_clipped) |
2458 | | return false; |
2459 | | //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] |
2460 | | |
2461 | | // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) |
2462 | | if (IsMouseHoveringRect(bb.Min, bb.Max)) |
2463 | | window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; |
2464 | | return true; |
| 3045 | // An active popup disable hovering on other windows (apart from its own children) |
| 3046 | // FIXME-OPT: This could be cached/stored within the window. |
| 3047 | ImGuiContext& g = *GImGui; |
| 3048 | if (g.NavWindow) |
| 3049 | if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) |
| 3050 | if (focused_root_window->WasActive && focused_root_window != window->RootWindow) |
| 3051 | { |
| 3052 | // For the purpose of those flags we differentiate "standard popup" from "modal popup" |
| 3053 | // NB: The order of those two tests is important because Modal windows are also Popups. |
| 3054 | if (focused_root_window->Flags & ImGuiWindowFlags_Modal) |
| 3055 | return false; |
| 3056 | if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) |
| 3057 | return false; |
| 3058 | } |
| 3059 | return true; |
2723 | | return &GImGui->DrawListSharedData; |
2724 | | } |
2725 | | |
2726 | | // This needs to be called before we submit any widget (aka in or before Begin) |
2727 | | void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) |
2728 | | { |
2729 | | ImGuiContext& g = *GImGui; |
2730 | | IM_ASSERT(window == g.NavWindow); |
2731 | | bool init_for_nav = false; |
2732 | | if (!(window->Flags & ImGuiWindowFlags_NoNavInputs)) |
2733 | | if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) |
2734 | | init_for_nav = true; |
2735 | | if (init_for_nav) |
2736 | | { |
2737 | | SetNavID(0, g.NavLayer); |
2738 | | g.NavInitRequest = true; |
2739 | | g.NavInitRequestFromMove = false; |
2740 | | g.NavInitResultId = 0; |
2741 | | g.NavInitResultRectRel = ImRect(); |
2742 | | NavUpdateAnyRequestFlag(); |
2743 | | } |
2744 | | else |
2745 | | { |
2746 | | g.NavId = window->NavLastIds[0]; |
2747 | | } |
2748 | | } |
2749 | | |
2750 | | static ImVec2 NavCalcPreferredRefPos() |
2751 | | { |
2752 | | ImGuiContext& g = *GImGui; |
2753 | | if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) |
2754 | | return ImFloor(g.IO.MousePos); |
2755 | | |
2756 | | // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item |
2757 | | const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; |
2758 | | ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); |
2759 | | ImRect visible_rect = GetViewportRect(); |
2760 | | return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta. |
2761 | | } |
2762 | | |
2763 | | static int FindWindowIndex(ImGuiWindow* window) // FIXME-OPT O(N) |
2764 | | { |
2765 | | ImGuiContext& g = *GImGui; |
2766 | | for (int i = g.Windows.Size - 1; i >= 0; i--) |
2767 | | if (g.Windows[i] == window) |
2768 | | return i; |
2769 | | return -1; |
2770 | | } |
2771 | | |
2772 | | static ImGuiWindow* FindWindowNavigable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) |
2773 | | { |
2774 | | ImGuiContext& g = *GImGui; |
2775 | | for (int i = i_start; i >= 0 && i < g.Windows.Size && i != i_stop; i += dir) |
2776 | | if (ImGui::IsWindowNavFocusable(g.Windows[i])) |
2777 | | return g.Windows[i]; |
2778 | | return NULL; |
2779 | | } |
2780 | | |
2781 | | float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) |
2782 | | { |
2783 | | ImGuiContext& g = *GImGui; |
2784 | | if (mode == ImGuiInputReadMode_Down) |
2785 | | return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user) |
2786 | | |
2787 | | const float t = g.IO.NavInputsDownDuration[n]; |
2788 | | if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input. |
2789 | | return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); |
2790 | | if (t < 0.0f) |
2791 | | return 0.0f; |
2792 | | if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input. |
2793 | | return (t == 0.0f) ? 1.0f : 0.0f; |
2794 | | if (mode == ImGuiInputReadMode_Repeat) |
2795 | | return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f); |
2796 | | if (mode == ImGuiInputReadMode_RepeatSlow) |
2797 | | return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f); |
2798 | | if (mode == ImGuiInputReadMode_RepeatFast) |
2799 | | return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f); |
2800 | | return 0.0f; |
2801 | | } |
2802 | | |
2803 | | // Equivalent of IsKeyDown() for NavInputs[] |
2804 | | static bool IsNavInputDown(ImGuiNavInput n) |
2805 | | { |
2806 | | return GImGui->IO.NavInputs[n] > 0.0f; |
2807 | | } |
2808 | | |
2809 | | // Equivalent of IsKeyPressed() for NavInputs[] |
2810 | | static bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) |
2811 | | { |
2812 | | return ImGui::GetNavInputAmount(n, mode) > 0.0f; |
2813 | | } |
2814 | | |
2815 | | static bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) |
2816 | | { |
2817 | | return (ImGui::GetNavInputAmount(n1, mode) + ImGui::GetNavInputAmount(n2, mode)) > 0.0f; |
2818 | | } |
2819 | | |
2820 | | ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor) |
2821 | | { |
2822 | | ImVec2 delta(0.0f, 0.0f); |
2823 | | if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) |
2824 | | delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); |
2825 | | if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) |
2826 | | delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); |
2827 | | if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) |
2828 | | delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); |
2829 | | if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) |
2830 | | delta *= slow_factor; |
2831 | | if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) |
2832 | | delta *= fast_factor; |
2833 | | return delta; |
2834 | | } |
2835 | | |
2836 | | static void NavUpdateWindowingHighlightWindow(int focus_change_dir) |
2837 | | { |
2838 | | ImGuiContext& g = *GImGui; |
2839 | | IM_ASSERT(g.NavWindowingTarget); |
2840 | | if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) |
2841 | | return; |
2842 | | |
2843 | | const int i_current = FindWindowIndex(g.NavWindowingTarget); |
2844 | | ImGuiWindow* window_target = FindWindowNavigable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); |
2845 | | if (!window_target) |
2846 | | window_target = FindWindowNavigable((focus_change_dir < 0) ? (g.Windows.Size - 1) : 0, i_current, focus_change_dir); |
2847 | | g.NavWindowingTarget = window_target; |
2848 | | g.NavWindowingToggleLayer = false; |
2849 | | } |
2850 | | |
2851 | | // Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer) |
2852 | | static void ImGui::NavUpdateWindowing() |
2853 | | { |
2854 | | ImGuiContext& g = *GImGui; |
2855 | | ImGuiWindow* apply_focus_window = NULL; |
2856 | | bool apply_toggle_layer = false; |
2857 | | |
2858 | | bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); |
2859 | | bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard); |
2860 | | if (start_windowing_with_gamepad || start_windowing_with_keyboard) |
2861 | | if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavigable(g.Windows.Size - 1, -INT_MAX, -1)) |
2862 | | { |
2863 | | g.NavWindowingTarget = window->RootWindowForTabbing; |
2864 | | g.NavWindowingHighlightTimer = g.NavWindowingHighlightAlpha = 0.0f; |
2865 | | g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true; |
2866 | | g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad; |
2867 | | } |
2868 | | |
2869 | | // Gamepad update |
2870 | | g.NavWindowingHighlightTimer += g.IO.DeltaTime; |
2871 | | if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad) |
2872 | | { |
2873 | | // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise |
2874 | | g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.20f) / 0.05f)); |
2875 | | |
2876 | | // Select window to focus |
2877 | | const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow); |
2878 | | if (focus_change_dir != 0) |
2879 | | { |
2880 | | NavUpdateWindowingHighlightWindow(focus_change_dir); |
2881 | | g.NavWindowingHighlightAlpha = 1.0f; |
2882 | | } |
2883 | | |
2884 | | // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most) |
2885 | | if (!IsNavInputDown(ImGuiNavInput_Menu)) |
2886 | | { |
2887 | | g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. |
2888 | | if (g.NavWindowingToggleLayer && g.NavWindow) |
2889 | | apply_toggle_layer = true; |
2890 | | else if (!g.NavWindowingToggleLayer) |
2891 | | apply_focus_window = g.NavWindowingTarget; |
2892 | | g.NavWindowingTarget = NULL; |
2893 | | } |
2894 | | } |
2895 | | |
2896 | | // Keyboard: Focus |
2897 | | if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard) |
2898 | | { |
2899 | | // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise |
2900 | | g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.15f) / 0.04f)); // 1.0f |
2901 | | if (IsKeyPressedMap(ImGuiKey_Tab, true)) |
2902 | | NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1); |
2903 | | if (!g.IO.KeyCtrl) |
2904 | | apply_focus_window = g.NavWindowingTarget; |
2905 | | } |
2906 | | |
2907 | | // Keyboard: Press and Release ALT to toggle menu layer |
2908 | | // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB |
2909 | | if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released)) |
2910 | | if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev)) |
2911 | | apply_toggle_layer = true; |
2912 | | |
2913 | | // Move window |
2914 | | if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) |
2915 | | { |
2916 | | ImVec2 move_delta; |
2917 | | if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift) |
2918 | | move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down); |
2919 | | if (g.NavInputSource == ImGuiInputSource_NavGamepad) |
2920 | | move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down); |
2921 | | if (move_delta.x != 0.0f || move_delta.y != 0.0f) |
2922 | | { |
2923 | | const float NAV_MOVE_SPEED = 800.0f; |
2924 | | const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well |
2925 | | g.NavWindowingTarget->Pos += move_delta * move_speed; |
2926 | | g.NavDisableMouseHover = true; |
2927 | | MarkIniSettingsDirty(g.NavWindowingTarget); |
2928 | | } |
2929 | | } |
2930 | | |
2931 | | // Apply final focus |
2932 | | if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindowForTabbing)) |
2933 | | { |
2934 | | g.NavDisableHighlight = false; |
2935 | | g.NavDisableMouseHover = true; |
2936 | | apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); |
2937 | | ClosePopupsOverWindow(apply_focus_window); |
2938 | | FocusWindow(apply_focus_window); |
2939 | | if (apply_focus_window->NavLastIds[0] == 0) |
2940 | | NavInitWindow(apply_focus_window, false); |
2941 | | |
2942 | | // If the window only has a menu layer, select it directly |
2943 | | if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1)) |
2944 | | g.NavLayer = 1; |
2945 | | } |
2946 | | if (apply_focus_window) |
2947 | | g.NavWindowingTarget = NULL; |
2948 | | |
2949 | | // Apply menu/layer toggle |
2950 | | if (apply_toggle_layer && g.NavWindow) |
2951 | | { |
2952 | | ImGuiWindow* new_nav_window = g.NavWindow; |
2953 | | while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) |
2954 | | new_nav_window = new_nav_window->ParentWindow; |
2955 | | if (new_nav_window != g.NavWindow) |
2956 | | { |
2957 | | ImGuiWindow* old_nav_window = g.NavWindow; |
2958 | | FocusWindow(new_nav_window); |
2959 | | new_nav_window->NavLastChildNavWindow = old_nav_window; |
2960 | | } |
2961 | | g.NavDisableHighlight = false; |
2962 | | g.NavDisableMouseHover = true; |
2963 | | NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0); |
2964 | | } |
2965 | | } |
2966 | | |
2967 | | // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated. |
2968 | | static void NavScrollToBringItemIntoView(ImGuiWindow* window, ImRect& item_rect_rel) |
2969 | | { |
2970 | | // Scroll to keep newly navigated item fully into view |
2971 | | ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1)); |
2972 | | //g.OverlayDrawList.AddRect(window->Pos + window_rect_rel.Min, window->Pos + window_rect_rel.Max, IM_COL32_WHITE); // [DEBUG] |
2973 | | if (window_rect_rel.Contains(item_rect_rel)) |
2974 | | return; |
2975 | | |
2976 | | ImGuiContext& g = *GImGui; |
2977 | | if (window->ScrollbarX && item_rect_rel.Min.x < window_rect_rel.Min.x) |
2978 | | { |
2979 | | window->ScrollTarget.x = item_rect_rel.Min.x + window->Scroll.x - g.Style.ItemSpacing.x; |
2980 | | window->ScrollTargetCenterRatio.x = 0.0f; |
2981 | | } |
2982 | | else if (window->ScrollbarX && item_rect_rel.Max.x >= window_rect_rel.Max.x) |
2983 | | { |
2984 | | window->ScrollTarget.x = item_rect_rel.Max.x + window->Scroll.x + g.Style.ItemSpacing.x; |
2985 | | window->ScrollTargetCenterRatio.x = 1.0f; |
2986 | | } |
2987 | | if (item_rect_rel.Min.y < window_rect_rel.Min.y) |
2988 | | { |
2989 | | window->ScrollTarget.y = item_rect_rel.Min.y + window->Scroll.y - g.Style.ItemSpacing.y; |
2990 | | window->ScrollTargetCenterRatio.y = 0.0f; |
2991 | | } |
2992 | | else if (item_rect_rel.Max.y >= window_rect_rel.Max.y) |
2993 | | { |
2994 | | window->ScrollTarget.y = item_rect_rel.Max.y + window->Scroll.y + g.Style.ItemSpacing.y; |
2995 | | window->ScrollTargetCenterRatio.y = 1.0f; |
2996 | | } |
2997 | | |
2998 | | // Estimate upcoming scroll so we can offset our relative mouse position so mouse position can be applied immediately (under this block) |
2999 | | ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); |
3000 | | item_rect_rel.Translate(window->Scroll - next_scroll); |
3001 | | } |
3002 | | |
3003 | | static void ImGui::NavUpdate() |
3004 | | { |
3005 | | ImGuiContext& g = *GImGui; |
3006 | | g.IO.WantSetMousePos = false; |
3007 | | |
3008 | | #if 0 |
3009 | | if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); |
| 3348 | return &GImGui->DrawListSharedData; |
| 3349 | } |
| 3350 | |
| 3351 | void ImGui::StartMouseMovingWindow(ImGuiWindow* window) |
| 3352 | { |
| 3353 | // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. |
| 3354 | // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. |
| 3355 | // This is because we want ActiveId to be set even when the window is not permitted to move. |
| 3356 | ImGuiContext& g = *GImGui; |
| 3357 | FocusWindow(window); |
| 3358 | SetActiveID(window->MoveId, window); |
| 3359 | g.NavDisableHighlight = true; |
| 3360 | g.ActiveIdNoClearOnFocusLoss = true; |
| 3361 | g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos; |
| 3362 | |
| 3363 | bool can_move_window = true; |
| 3364 | if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) |
| 3365 | &nbs |