Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/wolfpld/tracy.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/imgui
diff options
context:
space:
mode:
authorBartosz Taudul <wolf.pld@gmail.com>2019-11-26 00:36:54 +0300
committerBartosz Taudul <wolf.pld@gmail.com>2019-11-26 00:36:54 +0300
commitc6b8c6a3a6751724bdfab16083f8a9fea5469a8f (patch)
treea8d87f3147313f2431bbdc54a771920cc6636f94 /imgui
parentf500f6e8372e6b6b7c303b07381d6bf5cdbec3f1 (diff)
Update ImGui to 1.74.
Diffstat (limited to 'imgui')
-rw-r--r--imgui/imconfig.h13
-rw-r--r--imgui/imgui.cpp1085
-rw-r--r--imgui/imgui.h145
-rw-r--r--imgui/imgui_demo.cpp333
-rw-r--r--imgui/imgui_draw.cpp48
-rw-r--r--imgui/imgui_internal.h319
-rw-r--r--imgui/imgui_widgets.cpp485
-rw-r--r--imgui/imstb_textedit.h2
-rw-r--r--imgui/imstb_truetype.h2
9 files changed, 1326 insertions, 1106 deletions
diff --git a/imgui/imconfig.h b/imgui/imconfig.h
index 3c88b3af..279acdb6 100644
--- a/imgui/imconfig.h
+++ b/imgui/imconfig.h
@@ -34,9 +34,10 @@
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
-//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices').
-//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf.
-//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h.
+//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
+//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
+//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
+//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//---- Include imgui_user.h at the end of imgui.h as a convenience
@@ -64,9 +65,9 @@
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
-//---- Using 32-bits vertex indices (default is 16-bits) is one way to allow large meshes with more than 64K vertices.
-// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bits indices).
-// Another way to allow large meshes while keeping 16-bits indices is to handle ImDrawCmd::VtxOffset in your renderer.
+//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
+// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices).
+// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
#define ImDrawIdx unsigned int
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index 93b15ddb..c2b489ad 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,12 +1,12 @@
-// dear imgui, v1.73
+// dear imgui, v1.74
// (main code and documentation)
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
// Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
// Get latest version at https://github.com/ocornut/imgui
// Releases change-log at https://github.com/ocornut/imgui/releases
-// Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started
-// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/2529
+// Technical Support for Getting Started https://github.com/ocornut/imgui/wiki
+// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/2847
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
// See LICENSE.txt for copyright and licensing details (standard MIT License).
@@ -28,34 +28,16 @@ DOCUMENTATION
- MISSION STATEMENT
- END-USER GUIDE
-- PROGRAMMER GUIDE (read me!)
- - Read first.
- - How to update to a newer version of Dear ImGui.
- - Getting started with integrating Dear ImGui in your code/engine.
- - This is how a simple application may look like (2 variations).
- - This is how a simple rendering function may look like.
- - Using gamepad/keyboard navigation controls.
+- PROGRAMMER GUIDE
+ - READ FIRST
+ - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
+ - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
+ - HOW A SIMPLE APPLICATION MAY LOOK LIKE (2 variations)
+ - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
+ - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
- API BREAKING CHANGES (read me when you update!)
-- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
- - Where is the documentation?
- - Which version should I get?
- - Who uses Dear ImGui?
- - Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- - How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
- - How can I display an image? What is ImTextureID, how does it works?
- - Why are multiple widgets reacting when I interact with a single one? How can I have
- multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack...
- - How can I use my own math types instead of ImVec2/ImVec4?
- - How can I load a different font than the default?
- - How can I easily use icons in my application?
- - How can I load multiple fonts?
- - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
- - How can I interact with standard C++ types (such as std::string and std::vector)?
- - How can I use the drawing facilities without a Dear ImGui window? (using ImDrawList API)
- - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad)
- - I integrated Dear ImGui in my engine and the text or lines are blurry..
- - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
- - How can I help?
+- FREQUENTLY ASKED QUESTIONS (FAQ)
+ - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer)
CODE
(search for "[SECTION]" in the code to find them)
@@ -63,7 +45,8 @@ CODE
// [SECTION] FORWARD DECLARATIONS
// [SECTION] CONTEXT AND MEMORY ALLOCATORS
// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
-// [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions)
+// [SECTION] MISC HELPERS/UTILITIES (Geomtry, String, Format, Hash, File functions)
+// [SECTION] MISC HELPERS/UTILITIES (File functions)
// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
// [SECTION] MISC HELPERS/UTILITIES (Color functions)
// [SECTION] ImGuiStorage
@@ -72,6 +55,7 @@ CODE
// [SECTION] ImGuiListClipper
// [SECTION] RENDER HELPERS
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
+// [SECTION] ERROR CHECKING
// [SECTION] SCROLLING
// [SECTION] TOOLTIPS
// [SECTION] POPUPS
@@ -135,9 +119,9 @@ CODE
PROGRAMMER GUIDE
================
- READ FIRST:
-
- - Read the FAQ below this section!
+ READ FIRST
+ ----------
+ - Remember to read the FAQ (https://www.dearimgui.org/faq)
- 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
or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs.
- Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
@@ -157,8 +141,8 @@ CODE
However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase.
- C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!).
- HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI:
-
+ HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
+ ----------------------------------------------
- Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
- Or maintain your own branch where you have imconfig.h modified.
- Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
@@ -167,8 +151,8 @@ CODE
likely be a comment about it. Please report any issue to the GitHub page!
- Try to keep your copy of dear imgui reasonably up to date.
- GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE:
-
+ GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
+ ---------------------------------------------------------------
- Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
- Add the Dear ImGui source files to your projects or using your preferred build system.
It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL).
@@ -180,7 +164,8 @@ CODE
- Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code.
- 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.
- HOW A SIMPLE APPLICATION MAY LOOK LIKE:
+ HOW A SIMPLE APPLICATION MAY LOOK LIKE
+ --------------------------------------
EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder).
// Application init: create a dear imgui context, setup some options, load fonts
@@ -216,8 +201,7 @@ CODE
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
- HOW A SIMPLE APPLICATION MAY LOOK LIKE:
- EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE.
+ EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE
// Application init: create a dear imgui context, setup some options, load fonts
ImGui::CreateContext();
@@ -234,7 +218,7 @@ CODE
// At this point you've got the texture data and you need to upload that your your graphic system:
// After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
- // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ below for details about ImTextureID.
+ // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.
MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
io.Fonts->TexID = (void*)texture;
@@ -271,8 +255,8 @@ CODE
// Shutdown
ImGui::DestroyContext();
- HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE:
-
+ HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
+ ---------------------------------------------
void void MyImGuiRenderFunction(ImDrawData* draw_data)
{
// TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
@@ -309,7 +293,7 @@ CODE
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));
// Render 'pcmd->ElemCount/3' indexed triangles.
- // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits in imconfig.h if your engine doesn't support 16-bits indices.
+ // 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.
MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
}
idx_buffer += pcmd->ElemCount;
@@ -320,11 +304,11 @@ CODE
- The examples/ folders contains many actual implementation of the pseudo-codes above.
- When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the
- rest of your application. In every cases you need to pass on the inputs to Dear ImGui. Refer to the FAQ for more information.
- - Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues!
+ rest of your application. In every cases you need to pass on the inputs to Dear ImGui.
+ - Refer to the FAQ for more information. Amusingly, it is called a FAQ because people frequently run into the same issues!
USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
-
+ ------------------------------------------
- The gamepad/keyboard navigation is fairly functional and keeps being improved.
- Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse!
- You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
@@ -369,9 +353,17 @@ CODE
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.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
+ - 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.
+ - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
+ - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
+ - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): Begin() (5 arguments signature), IsRootWindowOrAnyChildHovered(), AlignFirstTextHeightToWidgets(), SetNextWindowPosCenter(), ImFont::Glyph. See docs/Changelog.txt or grep this log for details and new names, or see how they were implemented until 1.73.
+ - 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.
+ 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.
+ 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).
+ If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
- 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
- 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
- - 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.
+ - 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.
- 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
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.
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.
@@ -482,14 +474,9 @@ CODE
- 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.
- 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.
- 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
- If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
- 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.
- 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.
- 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);
- }
+ 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.
+ 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:
+ 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); }
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.
- 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
- 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
@@ -569,8 +556,14 @@ CODE
- 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
- ======================================
+ FREQUENTLY ASKED QUESTIONS (FAQ)
+ ================================
+
+ Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer)
+ Some answers are copied down here to facilitate searching in code.
+
+ Q&A: Basics
+ ===========
Q: Where is the documentation?
A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
@@ -584,26 +577,20 @@ CODE
associated to it.
Q: Which version should I get?
- A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
- and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
- fixed fast when reported. You may also peak at the 'docking' branch which includes:
- - Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
- - Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
- Many projects are using this branch and it is kept in sync with master regularly.
+ Q: Why the names "Dear ImGui" vs "ImGui"?
+ >> See https://www.dearimgui.org/faq
+
+ Q&A: Concerns
+ =============
Q: Who uses Dear ImGui?
- A: See "Quotes" (https://github.com/ocornut/imgui/wiki/Quotes) and
- "Software using Dear ImGui" (https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages
- for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
-
- Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
- when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
- (immediate-mode graphical user interface) was coined before and is being used in variety of other
- situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
- To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
- longer name "Dear ImGui" that people can use to refer to this specific library.
- Please try to refer to this library as "Dear ImGui".
+ Q: Can you create elaborate/serious tools with Dear ImGui?
+ Q: Can you reskin the look of Dear ImGui?
+ Q: Why using C++ (as opposed to C)?
+ >> See https://www.dearimgui.org/faq
+
+ Q&A: Integration
+ ================
Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
@@ -620,75 +607,13 @@ CODE
have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs
were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.)
- Q: How can I display an image? What is ImTextureID, how does it works?
- A: Short explanation:
- - Please read Wiki entry for examples: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
- - You may use functions such as ImGui::Image(), ImGui::ImageButton() or lower-level ImDrawList::AddImage() to emit draw calls that will use your own textures.
- - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value.
- - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason).
- Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.
-
- Long explanation:
- - Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices.
- At the end of the frame those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code
- to render them is generally fairly short (a few dozen lines). In the examples/ folder we provide functions for popular graphics API (OpenGL, DirectX, etc.).
- - Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API.
- We carry the information to identify a "texture" in the ImTextureID type.
- ImTextureID is nothing more that a void*, aka 4/8 bytes worth of data: just enough to store 1 pointer or 1 integer of your choice.
- Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function.
- - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying
- an image from the end-user perspective. This is what the _examples_ rendering functions are using:
-
- OpenGL: ImTextureID = GLuint (see ImGui_ImplOpenGL3_RenderDrawData() function in imgui_impl_opengl3.cpp)
- DirectX9: ImTextureID = LPDIRECT3DTEXTURE9 (see ImGui_ImplDX9_RenderDrawData() function in imgui_impl_dx9.cpp)
- DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp)
- DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp)
-
- For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID.
- Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure
- tying together both the texture and information about its format and how to read it.
- - If you have a custom engine built over e.g. OpenGL, instead of passing GLuint around you may decide to use a high-level data type to carry information about
- the texture as well as how to display it (shaders, etc.). The decision of what to use as ImTextureID can always be made better knowing how your codebase
- is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them.
- If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID
- representation suggested by the example bindings is probably the best choice.
- (Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer)
-
- User code may do:
-
- // Cast our texture type to ImTextureID / void*
- MyTexture* texture = g_CoffeeTableTexture;
- ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height));
-
- The renderer function called after ImGui::Render() will receive that same value that the user code passed:
-
- // Cast ImTextureID / void* stored in the draw command as our texture type
- MyTexture* texture = (MyTexture*)pcmd->TextureId;
- MyEngineBindTexture2D(texture);
-
- Once you understand this design you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui.
- This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them.
- If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using.
-
- Refer to the Wiki to find simplified examples for loading textures with OpenGL, DirectX9 and DirectX11:
-
- https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
-
- C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTextureID / void*, and vice-versa.
- Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTextureID / void*.
- Examples:
-
- GLuint my_tex = XXX;
- void* my_void_ptr;
- my_void_ptr = (void*)(intptr_t)my_tex; // cast a GLuint into a void* (we don't take its address! we literally store the value inside the pointer)
- my_tex = (GLuint)(intptr_t)my_void_ptr; // cast a void* into a GLuint
-
- ID3D11ShaderResourceView* my_dx11_srv = XXX;
- void* my_void_ptr;
- my_void_ptr = (void*)my_dx11_srv; // cast a ID3D11ShaderResourceView* into an opaque void*
- my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr; // cast a void* into a ID3D11ShaderResourceView*
-
- Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
+ Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
+ Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
+ Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
+ >> See https://www.dearimgui.org/faq
+
+ Q&A: Usage
+ ----------
Q: Why are multiple widgets reacting when I interact with a single one?
Q: How can I have multiple widgets with the same label or with an empty label?
@@ -806,141 +731,25 @@ CODE
e.g. when displaying a list of objects, using indices or pointers as ID will preserve the
node open/closed state differently. See what makes more sense in your situation!
+ Q: How can I display an image? What is ImTextureID, how does it works?
+ >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
+
Q: How can I use my own math types instead of ImVec2/ImVec4?
- A: You can edit imconfig.h and setup the IM_VEC2_CLASS_EXTRA/IM_VEC4_CLASS_EXTRA macros to add implicit type conversions.
- This way you'll be able to use your own types everywhere, e.g. passing glm::vec2 to ImGui functions instead of ImVec2.
+ Q: How can I interact with standard C++ types (such as std::string and std::vector)?
+ Q: How can I display custom shapes? (using low-level ImDrawList API)
+ >> See https://www.dearimgui.org/faq
- Q: How can I load a different font than the default?
- A: Use the font atlas to load the TTF/OTF file you want:
- ImGuiIO& io = ImGui::GetIO();
- io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
- io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
- Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear imgui's source code.
- (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.)
- (Read the 'misc/fonts/README.txt' file for more details about font loading.)
-
- New programmers: remember that in C/C++ and most programming languages if you want to use a
- backslash \ within a string literal, you need to write it double backslash "\\":
- io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG (you are escape the M here!)
- io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT
- io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT
+ Q&A: Fonts, Text
+ ================
+ Q: How can I load a different font than the default?
Q: How can I easily use icons in my application?
- A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you
- main font. Then you can refer to icons within your strings.
- You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment.
- (Read the 'misc/fonts/README.txt' file for more details about icons font loading.)
- With some extra effort, you may use colorful icon by registering custom rectangle space inside the font atlas,
- and copying your own graphics data into it. See misc/fonts/README.txt about using the AddCustomRectFontGlyph API.
-
Q: How can I load multiple fonts?
- A: Use the font atlas to pack them into a single texture:
- (Read the 'misc/fonts/README.txt' file and the code in ImFontAtlas for more details.)
-
- ImGuiIO& io = ImGui::GetIO();
- ImFont* font0 = io.Fonts->AddFontDefault();
- ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
- ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
- io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
- // the first loaded font gets used by default
- // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
-
- // Options
- ImFontConfig config;
- config.OversampleH = 2;
- config.OversampleV = 1;
- config.GlyphOffset.y -= 1.0f; // Move everything by 1 pixels up
- config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters
- io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, &config);
-
- // Combine multiple fonts into one (e.g. for icon fonts)
- static ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
- ImFontConfig config;
- config.MergeMode = true;
- io.Fonts->AddFontDefault();
- io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font
- io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs
-
Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
- A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
-
- // Add default Japanese ranges
- io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
-
- // 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)
- ImVector<ImWchar> ranges;
- ImFontGlyphRangesBuilder builder;
- builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
- builder.AddChar(0x7262); // Add a specific character
- builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
- builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
- io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
-
- All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8
- by using the u8"hello" syntax. Specifying literal in your source code using a local code page
- (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
- Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
-
- Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter().
- The applications in examples/ are doing that.
- Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode).
- You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state.
- Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for
- the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly.
-
- Q: How can I interact with standard C++ types (such as std::string and std::vector)?
- A: - Being highly portable (bindings for several languages, frameworks, programming style, obscure or older platforms/compilers),
- and aiming for compatibility & performance suitable for every modern real-time game engines, dear imgui does not use
- any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases.
- - To use ImGui::InputText() with a std::string or any resizable string class, see misc/cpp/imgui_stdlib.h.
- - To use combo boxes and list boxes with std::vector or any other data structure: the BeginCombo()/EndCombo() API
- lets you iterate and submit items yourself, so does the ListBoxHeader()/ListBoxFooter() API.
- Prefer using them over the old and awkward Combo()/ListBox() api.
- - Generally for most high-level types you should be able to access the underlying data type.
- You may write your own one-liner wrappers to facilitate user code (tip: add new functions in ImGui:: namespace from your code).
- - Dear ImGui applications often need to make intensive use of strings. It is expected that many of the strings you will pass
- to the API are raw literals (free in C/C++) or allocated in a manner that won't incur a large cost on your application.
- Please bear in mind that using std::string on applications with large amount of UI may incur unsatisfactory performances.
- Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those
- are not configurable and not the same across implementations.
- - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount
- of heap allocations. Consider using literals, statically sized buffers and your own helper functions. A common pattern
- is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead.
- One possible implementation of a helper to facilitate printf-style building of strings: https://github.com/ocornut/Str
- This is a small helper where you can instance strings with configurable local buffers length. Many game engines will
- provide similar or better string helpers.
-
- Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
- A: - You can create a dummy window. Call Begin() with the NoBackground | NoDecoration | NoSavedSettings | NoInputs flags.
- (The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse)
- Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
- - You can call ImGui::GetBackgroundDrawList() or ImGui::GetForegroundDrawList() and use those draw list to display
- contents behind or over every other imgui windows (one bg/fg drawlist per viewport).
- - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create
- your own ImDrawListSharedData, and then call your rendered code with your own ImDrawList or ImDrawData data.
+ >> See https://www.dearimgui.org/faq and docs/FONTS.txt
- Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
- A: - You can control Dear ImGui with a gamepad. Read about navigation in "Using gamepad/keyboard navigation controls".
- (short version: map gamepad inputs into the io.NavInputs[] array + set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad)
- - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy)
- This is the preferred solution for developer productivity.
- In particular, the "micro-synergy-client" repository (https://github.com/symless/micro-synergy-client) has simple
- and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect
- to your host computer, based on the Synergy 1.x protocol. Make sure you download the Synergy 1 server on your computer.
- Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-like protocols.
- - You may also use a third party solution such as Remote ImGui (https://github.com/JordiRos/remoteimgui) which sends
- the vertices to render over the local network, allowing you to use Dear ImGui even on a screen-less machine.
- - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate
- for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing
- for screen real-estate and precision.
-
- Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
- A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
- Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
-
- Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
- A: You are probably mishandling the clipping rectangles in your render function.
- Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
+ Q&A: Community
+ ==============
Q: How can I help?
A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt
@@ -948,18 +757,10 @@ CODE
- Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui.
- Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README.
- Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
- You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1902). Visuals are ideal as they inspire other programmers.
+ You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/2847). Visuals are ideal as they inspire other programmers.
But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
- 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).
- - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
- this is also useful to set yourself in the context of another window (to get/set other settings)
- - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug".
- - 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
- of a deep nested inner loop in your code.
- - tip: you can call Render() multiple times (e.g for VR renders).
- - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui!
-
*/
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
@@ -1037,7 +838,6 @@ static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock
static void SetCurrentWindow(ImGuiWindow* window);
static void FindHoveredWindow();
static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
-static void CheckStacksSize(ImGuiWindow* window, bool write);
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges);
static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
@@ -1046,9 +846,9 @@ static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted
static ImRect GetViewportRect();
// Settings
-static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
-static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
-static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf);
+static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
+static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
+static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
// Platform Dependents default implementation for IO functions
static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
@@ -1064,7 +864,7 @@ static void NavUpdate();
static void NavUpdateWindowing();
static void NavUpdateWindowingOverlay();
static void NavUpdateMoveResult();
-static float NavUpdatePageUpPageDown(int allowed_dir_flags);
+static float NavUpdatePageUpPageDown();
static inline void NavUpdateAnyRequestFlag();
static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
@@ -1073,6 +873,10 @@ static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_win
static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
static int FindWindowFocusIndex(ImGuiWindow* window);
+// Error Checking
+static void ErrorCheckEndFrame();
+static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write);
+
// Misc
static void UpdateMouseInputs();
static void UpdateMouseWheel();
@@ -1209,7 +1013,7 @@ ImGuiIO::ImGuiIO()
MouseDoubleClickMaxDist = 6.0f;
for (int i = 0; i < ImGuiKey_COUNT; i++)
KeyMap[i] = -1;
- KeyRepeatDelay = 0.250f;
+ KeyRepeatDelay = 0.275f;
KeyRepeatRate = 0.050f;
UserData = NULL;
@@ -1258,7 +1062,7 @@ ImGuiIO::ImGuiIO()
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
void ImGuiIO::AddInputCharacter(unsigned int c)
{
- if (c > 0 && c < 0x10000)
+ if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX)
InputQueueCharacters.push_back((ImWchar)c);
}
@@ -1268,7 +1072,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{
unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
- if (c > 0 && c < 0x10000)
+ if (c > 0 && c <= IM_UNICODE_CODEPOINT_MAX)
InputQueueCharacters.push_back((ImWchar)c);
}
}
@@ -1279,7 +1083,7 @@ void ImGuiIO::ClearInputCharacters()
}
//-----------------------------------------------------------------------------
-// [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions)
+// [SECTION] MISC HELPERS/UTILITIES (Geometry, String, Format, Hash, File functions)
//-----------------------------------------------------------------------------
ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
@@ -1383,7 +1187,7 @@ const char* ImStrchrRange(const char* str, const char* str_end, char c)
int ImStrlenW(const ImWchar* str)
{
- //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bits
+ //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit
int n = 0;
while (*str++) n++;
return n;
@@ -1441,15 +1245,26 @@ void ImStrTrimBlanks(char* buf)
buf[p - p_start] = 0; // Zero terminate
}
+const char* ImStrSkipBlank(const char* str)
+{
+ while (str[0] == ' ' || str[0] == '\t')
+ str++;
+ return str;
+}
+
// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
// B) When buf==NULL vsnprintf() will return the output size.
-#ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
+#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
+// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
+// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
+// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
+// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
//#define IMGUI_USE_STB_SPRINTF
#ifdef IMGUI_USE_STB_SPRINTF
#define STB_SPRINTF_IMPLEMENTATION
-#include "imstb_sprintf.h"
+#include "stb_sprintf.h"
#endif
#if defined(_MSC_VER) && !defined(vsnprintf)
@@ -1488,7 +1303,7 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
buf[w] = 0;
return w;
}
-#endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
+#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
// CRC32 needs a 1KB lookup table (not cache friendly)
// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
@@ -1560,10 +1375,16 @@ ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed)
return ~crc;
}
-FILE* ImFileOpen(const char* filename, const char* mode)
+//-----------------------------------------------------------------------------
+// [SECTION] MISC HELPERS/UTILITIES (File functions)
+//-----------------------------------------------------------------------------
+
+// Default file functions
+#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
+ImFileHandle ImFileOpen(const char* filename, const char* mode)
{
-#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__)
- // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can)
+#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
+ // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
ImVector<ImWchar> buf;
@@ -1576,42 +1397,48 @@ FILE* ImFileOpen(const char* filename, const char* mode)
#endif
}
-// Load file content into memory
+// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way.
+bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; }
+ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; }
+ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); }
+ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); }
+#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
+
+// Helper: Load file content into memory
// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
-void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
+void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
{
- IM_ASSERT(filename && file_open_mode);
+ IM_ASSERT(filename && mode);
if (out_file_size)
*out_file_size = 0;
- FILE* f;
- if ((f = ImFileOpen(filename, file_open_mode)) == NULL)
+ ImFileHandle f;
+ if ((f = ImFileOpen(filename, mode)) == NULL)
return NULL;
- long file_size_signed;
- if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
+ size_t file_size = (size_t)ImFileGetSize(f);
+ if (file_size == (size_t)-1)
{
- fclose(f);
+ ImFileClose(f);
return NULL;
}
- size_t file_size = (size_t)file_size_signed;
void* file_data = IM_ALLOC(file_size + padding_bytes);
if (file_data == NULL)
{
- fclose(f);
+ ImFileClose(f);
return NULL;
}
- if (fread(file_data, 1, file_size, f) != file_size)
+ if (ImFileRead(file_data, 1, file_size, f) != file_size)
{
- fclose(f);
+ ImFileClose(f);
IM_FREE(file_data);
return NULL;
}
if (padding_bytes > 0)
memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
- fclose(f);
+ ImFileClose(f);
if (out_file_size)
*out_file_size = file_size;
@@ -1622,7 +1449,7 @@ void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_
// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
//-----------------------------------------------------------------------------
-// Convert UTF-8 to 32-bits character, process single character input.
+// Convert UTF-8 to 32-bit character, process single character input.
// Based on stb_from_utf8() from github.com/nothings/stb/
// We handle UTF-8 decoding error by skipping forward.
int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
@@ -1637,7 +1464,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char*
}
if ((*str & 0xe0) == 0xc0)
{
- *out_char = 0xFFFD; // will be invalid but not end of string
+ *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
if (in_text_end && in_text_end - (const char*)str < 2) return 1;
if (*str < 0xc2) return 2;
c = (unsigned int)((*str++ & 0x1f) << 6);
@@ -1648,7 +1475,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char*
}
if ((*str & 0xf0) == 0xe0)
{
- *out_char = 0xFFFD; // will be invalid but not end of string
+ *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
if (in_text_end && in_text_end - (const char*)str < 3) return 1;
if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
@@ -1662,7 +1489,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char*
}
if ((*str & 0xf8) == 0xf0)
{
- *out_char = 0xFFFD; // will be invalid but not end of string
+ *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
if (in_text_end && in_text_end - (const char*)str < 4) return 1;
if (*str > 0xf4) return 4;
if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
@@ -1693,7 +1520,7 @@ int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const cha
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0)
break;
- if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
+ if (c <= IM_UNICODE_CODEPOINT_MAX) // FIXME: Losing characters that don't fit in 2 bytes
*buf_out++ = (ImWchar)c;
}
*buf_out = 0;
@@ -1711,7 +1538,7 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
if (c == 0)
break;
- if (c < 0x10000)
+ if (c <= IM_UNICODE_CODEPOINT_MAX)
char_count++;
}
return char_count;
@@ -2507,7 +2334,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side
float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis
-
+
if (ellipsis_char_count > 1)
{
// Full ellipsis size without free spacing after it.
@@ -2515,7 +2342,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
}
-
+
// We can now claim the space between pos_max.x and ellipsis_max.x
const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
@@ -2711,11 +2538,13 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
+ InnerRect = ImRect(0.0f, 0.0f, 0.0f, 0.0f); // Clear so the InnerRect.GetSize() code in Begin() doesn't lead to overflow even if the result isn't used.
+
LastFrameActive = -1;
LastTimeActive = -1.0f;
ItemWidthDefault = 0.0f;
FontWindowScale = 1.0f;
- SettingsIdx = -1;
+ SettingsOffset = -1;
DrawList = &DrawListInst;
DrawList->_OwnerName = Name;
@@ -2865,8 +2694,6 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
}
}
g.ActiveId = id;
- g.ActiveIdAllowNavDirFlags = 0;
- g.ActiveIdBlockNavInputFlags = 0;
g.ActiveIdAllowOverlap = false;
g.ActiveIdWindow = window;
g.ActiveIdHasBeenEditedThisFrame = false;
@@ -2875,6 +2702,12 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
g.ActiveIdIsAlive = id;
g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
}
+
+ // Clear declaration of inputs claimed by the widget
+ // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
+ g.ActiveIdUsingNavDirMask = 0x00;
+ g.ActiveIdUsingNavInputMask = 0x00;
+ g.ActiveIdUsingKeyInputMask = 0x00;
}
// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring.
@@ -2963,37 +2796,42 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFla
}
// Advance cursor given item size for layout.
-void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
+void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems)
return;
+ // We increase the height in this function to accommodate for baseline offset.
+ // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
+ // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
+ const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
+ const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y);
+
// Always align ourselves on pixel boundaries
- const float line_height = ImMax(window->DC.CurrLineSize.y, size.y);
- const float text_base_offset = ImMax(window->DC.CurrLineTextBaseOffset, text_offset_y);
//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]
window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
- window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
- window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);
+ window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line
+ window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); // Next line
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
window->DC.PrevLineSize.y = line_height;
- window->DC.PrevLineTextBaseOffset = text_base_offset;
- window->DC.CurrLineSize.y = window->DC.CurrLineTextBaseOffset = 0.0f;
+ window->DC.CurrLineSize.y = 0.0f;
+ window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
+ window->DC.CurrLineTextBaseOffset = 0.0f;
// Horizontal layout mode
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
SameLine();
}
-void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
+void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
{
- ItemSize(bb.GetSize(), text_offset_y);
+ ItemSize(bb.GetSize(), text_baseline_y);
}
// Declare item bounding box for clipping and interaction.
@@ -3155,7 +2993,7 @@ bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
// Process TAB/Shift-TAB to tab *OUT* of the currently focused item.
// (Note that we can always TAB out of a widget that doesn't allow tabbing in)
- if (g.ActiveId == id && g.FocusTabPressed && !(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_KeyTab_)) && g.FocusRequestNextWindow == NULL)
+ if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL)
{
g.FocusRequestNextWindow = window;
g.FocusRequestNextCounterTab = window->DC.FocusCounterTab + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
@@ -3720,7 +3558,7 @@ void ImGui::NewFrame()
}
g.Time += g.IO.DeltaTime;
- g.FrameScopeActive = true;
+ g.WithinFrameScope = true;
g.FrameCount += 1;
g.TooltipOverrideCount = 0;
g.WindowsActiveCount = 0;
@@ -3780,6 +3618,11 @@ void ImGui::NewFrame()
g.ActiveIdIsJustActivated = false;
if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId)
g.TempInputTextId = 0;
+ if (g.ActiveId == 0)
+ {
+ g.ActiveIdUsingNavDirMask = g.ActiveIdUsingNavInputMask = 0;
+ g.ActiveIdUsingKeyInputMask = 0;
+ }
// Drag and drop
g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
@@ -3889,7 +3732,7 @@ void ImGui::NewFrame()
// This fallback is particularly important as it avoid ImGui:: calls from crashing.
SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver);
Begin("Debug##Default");
- g.FrameScopePushedImplicitWindow = true;
+ g.WithinFrameScopeWithImplicitWindow = true;
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiTestEngineHook_PostNewFrame(&g);
@@ -3927,13 +3770,15 @@ void ImGui::Initialize(ImGuiContext* context)
IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
// Add .ini handle for ImGuiWindow type
- ImGuiSettingsHandler ini_handler;
- ini_handler.TypeName = "Window";
- ini_handler.TypeHash = ImHashStr("Window");
- ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen;
- ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine;
- ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll;
- g.SettingsHandlers.push_back(ini_handler);
+ {
+ ImGuiSettingsHandler ini_handler;
+ ini_handler.TypeName = "Window";
+ ini_handler.TypeHash = ImHashStr("Window");
+ ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
+ ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
+ ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
+ g.SettingsHandlers.push_back(ini_handler);
+ }
g.Initialized = true;
}
@@ -3992,14 +3837,15 @@ void ImGui::Shutdown(ImGuiContext* context)
g.PrivateClipboard.clear();
g.InputTextState.ClearFreeMemory();
- for (int i = 0; i < g.SettingsWindows.Size; i++)
- IM_DELETE(g.SettingsWindows[i].Name);
g.SettingsWindows.clear();
g.SettingsHandlers.clear();
- if (g.LogFile && g.LogFile != stdout)
+ if (g.LogFile)
{
- fclose(g.LogFile);
+#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
+ if (g.LogFile != stdout)
+#endif
+ ImFileClose(g.LogFile);
g.LogFile = NULL;
}
g.LogBuffer.clear();
@@ -4065,7 +3911,7 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
// (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
// Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't.
// Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
- // (B) Or handle 32-bits indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
+ // (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
// Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
// glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
// Your own engine or render API may use different parameters or function calls to specify index sizes.
@@ -4158,7 +4004,7 @@ void ImGui::EndFrame()
IM_ASSERT(g.Initialized);
if (g.FrameCountEnded == g.FrameCount) // Don't process EndFrame() multiple times.
return;
- IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?");
+ IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
// Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f))
@@ -4167,24 +4013,10 @@ void ImGui::EndFrame()
g.PlatformImeLastPos = g.PlatformImePos;
}
- // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
- // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
- if (g.CurrentWindowStack.Size != 1)
- {
- if (g.CurrentWindowStack.Size > 1)
- {
- IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
- while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING
- End();
- }
- else
- {
- IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
- }
- }
+ ErrorCheckEndFrame();
// Hide implicit/fallback "Debug" window if it hasn't been used
- g.FrameScopePushedImplicitWindow = false;
+ g.WithinFrameScopeWithImplicitWindow = false;
if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
g.CurrentWindow->Active = false;
End();
@@ -4211,7 +4043,7 @@ void ImGui::EndFrame()
}
// End frame
- g.FrameScopeActive = false;
+ g.WithinFrameScope = false;
g.FrameCountEnded = g.FrameCount;
// Initiate moving window + handle left-click and right-click focus
@@ -4292,7 +4124,7 @@ void ImGui::Render()
}
// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
-// CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize)
+// CalcTextSize("") should return ImVec2(0.0f, g.FontSize)
ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
{
ImGuiContext& g = *GImGui;
@@ -4310,7 +4142,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex
ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
// Round
- text_size.x = (float)(int)(text_size.x + 0.95f);
+ text_size.x = IM_FLOOR(text_size.x + 0.95f);
return text_size;
}
@@ -4394,14 +4226,22 @@ bool ImGui::IsKeyDown(int user_key_index)
return g.IO.KeysDown[user_key_index];
}
-int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
+// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
+// t1 = current time (e.g.: g.Time)
+// An event is triggered at:
+// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N
+int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
{
- if (t == 0.0f)
+ if (t1 == 0.0f)
return 1;
- if (t <= repeat_delay || repeat_rate <= 0.0f)
+ if (t0 >= t1)
return 0;
- const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate);
- return (count > 0) ? count : 0;
+ if (repeat_rate <= 0.0f)
+ return (t0 < repeat_delay) && (t1 >= repeat_delay);
+ const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
+ const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
+ const int count = count_t1 - count_t0;
+ return count;
}
int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
@@ -4411,7 +4251,7 @@ int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_r
return 0;
IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
const float t = g.IO.KeysDownDuration[key_index];
- return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate);
+ return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
}
bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
@@ -4463,7 +4303,7 @@ bool ImGui::IsMouseClicked(int button, bool repeat)
if (repeat && t > g.IO.KeyRepeatDelay)
{
// FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold.
- int amount = CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.5f);
+ int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f);
if (amount > 0)
return true;
}
@@ -4626,6 +4466,12 @@ bool ImGui::IsItemClicked(int mouse_button)
return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
}
+bool ImGui::IsItemToggledOpen()
+{
+ ImGuiContext& g = *GImGui;
+ return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
+}
+
bool ImGui::IsItemToggledSelection()
{
ImGuiContext& g = *GImGui;
@@ -4764,7 +4610,10 @@ void ImGui::EndChild()
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
+ IM_ASSERT(g.WithinEndChild == false);
IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss
+
+ g.WithinEndChild = true;
if (window->BeginCount > 1)
{
End();
@@ -4796,6 +4645,7 @@ void ImGui::EndChild()
ItemAdd(bb, 0);
}
}
+ g.WithinEndChild = false;
}
// Helper to create a child window / scrolling region that looks like a normal widget frame.
@@ -4818,22 +4668,6 @@ void ImGui::EndChildFrame()
EndChild();
}
-// Save and compare stack sizes on Begin()/End() to detect usage errors
-static void CheckStacksSize(ImGuiWindow* window, bool write)
-{
- // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
- ImGuiContext& g = *GImGui;
- short* p_backup = &window->DC.StackSizesBackup[0];
- { int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop()
- { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup()
- { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
- // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
- { int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor()
- { int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar()
- { int current = g.FontStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!"); p_backup++; } // Too few or too many PopFont()
- IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
-}
-
static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
{
window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags);
@@ -4871,7 +4705,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
{
// Retrieve settings from .ini file
- window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
+ window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
window->Pos = ImVec2(settings->Pos.x, settings->Pos.y);
window->Collapsed = settings->Collapsed;
@@ -4922,8 +4756,8 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size
g.NextWindowData.SizeCallback(&data);
new_size = data.DesiredSize;
}
- new_size.x = ImFloor(new_size.x);
- new_size.y = ImFloor(new_size.y);
+ new_size.x = IM_FLOOR(new_size.x);
+ new_size.y = IM_FLOOR(new_size.y);
}
// Minimum size
@@ -4944,8 +4778,8 @@ static ImVec2 CalcWindowContentSize(ImGuiWindow* window)
return window->ContentSize;
ImVec2 sz;
- sz.x = (float)(int)((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
- sz.y = (float)(int)((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
+ sz.x = IM_FLOOR((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
+ sz.y = IM_FLOOR((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
return sz;
}
@@ -5024,10 +4858,10 @@ struct ImGuiResizeGripDef
static const ImGuiResizeGripDef resize_grip_def[4] =
{
- { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right
- { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left
- { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left
- { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right
+ { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower-right
+ { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower-left
+ { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper-left (Unused)
+ { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper-right (Unused)
};
static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
@@ -5042,6 +4876,17 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_
return ImRect();
}
+// 0..3: corners (Lower-right, Lower-left, Unused, Unused)
+// 4..7: borders (Top, Right, Bottom, Left)
+ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n)
+{
+ IM_ASSERT(n >= 0 && n <= 7);
+ ImGuiID id = window->ID;
+ id = ImHashStr("#RESIZE", 0, id);
+ id = ImHashData(&n, sizeof(int), id);
+ return id;
+}
+
// Handle resize for: Resize Grips, Borders, Gamepad
// Return true when using auto-fit (double click on resize grip)
static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
@@ -5056,8 +4901,8 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
bool ret_auto_fit = false;
const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
- const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
- const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f);
+ const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
+ const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
ImVec2 pos_target(FLT_MAX, FLT_MAX);
@@ -5079,7 +4924,7 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
bool hovered, held;
- ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
+ ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
//GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
if (hovered || held)
g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
@@ -5105,7 +4950,7 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
{
bool hovered, held;
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
- ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
+ ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
//GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
{
@@ -5216,6 +5061,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
ImGuiStyle& style = g.Style;
ImGuiWindowFlags flags = window->Flags;
+ // Ensure that ScrollBar doesn't read last frame's SkipItems
+ window->SkipItems = false;
+
// Draw window + handle manual resize
// As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame.
const float window_rounding = window->WindowRounding;
@@ -5365,7 +5213,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
if (flags & ImGuiWindowFlags_UnsavedDocument)
{
ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
- ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f));
+ ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f));
RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
}
}
@@ -5397,7 +5245,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required
- IM_ASSERT(g.FrameScopeActive); // Forgot to call ImGui::NewFrame()
+ IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame()
IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
// Find or create
@@ -5459,7 +5307,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
g.CurrentWindowStack.push_back(window);
g.CurrentWindow = NULL;
- CheckStacksSize(window, true);
+ ErrorCheckBeginEndCompareStacksSize(window, true);
if (flags & ImGuiWindowFlags_Popup)
{
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
@@ -5703,9 +5551,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Handle manual resize: Resize Grips, Borders, Gamepad
int border_held = -1;
- ImU32 resize_grip_col[4] = { 0 };
- const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4
- const float resize_grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
+ ImU32 resize_grip_col[4] = {};
+ const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
+ const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
if (!window->Collapsed)
if (UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]))
use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
@@ -5773,9 +5621,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Default item width. Make it proportional to window size if window manually resizes
if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
- window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
+ window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);
else
- window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
+ window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);
// SCROLLING
@@ -5864,14 +5712,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
- // [LEGACY] Contents Region
- // FIXME-OBSOLETE: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
+ // [LEGACY] Content Region
+ // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
// Used by:
// - Mouse wheel scrolling + many other things
- window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
- window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
- window->ContentsRegionRect.Max.x = window->ContentsRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
- window->ContentsRegionRect.Max.y = window->ContentsRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
+ window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
+ window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
+ window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
+ window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
// Setup drawing context
// (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
@@ -5995,35 +5843,24 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
return !skip_items;
}
-// Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead.
-#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
-bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags)
-{
- // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file.
- if (size_first_use.x != 0.0f || size_first_use.y != 0.0f)
- SetNextWindowSize(size_first_use, ImGuiCond_FirstUseEver);
-
- // Old API feature: override the window background alpha with a parameter.
- if (bg_alpha_override >= 0.0f)
- SetNextWindowBgAlpha(bg_alpha_override);
-
- return Begin(name, p_open, flags);
-}
-#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
-
void ImGui::End()
{
ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
- if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow)
+ // Error checking: verify that user hasn't called End() too many times!
+ if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow)
{
- IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!");
- return; // FIXME-ERRORHANDLING
+ IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
+ return;
}
IM_ASSERT(g.CurrentWindowStack.Size > 0);
- ImGuiWindow* window = g.CurrentWindow;
+ // Error checking: verify that user doesn't directly call End() on a child window.
+ if (window->Flags & ImGuiWindowFlags_ChildWindow)
+ IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!");
+ // Close anything that is open
if (window->DC.CurrentColumns)
EndColumns();
PopClipRect(); // Inner window clip rectangle
@@ -6036,7 +5873,7 @@ void ImGui::End()
g.CurrentWindowStack.pop_back();
if (window->Flags & ImGuiWindowFlags_Popup)
g.BeginPopupStack.pop_back();
- CheckStacksSize(window, false);
+ ErrorCheckBeginEndCompareStacksSize(window, false);
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
}
@@ -6169,8 +6006,8 @@ void ImGui::PushMultiItemsWidths(int components, float w_full)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const ImGuiStyle& style = g.Style;
- const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
- const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
+ const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
+ const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
window->DC.ItemWidthStack.push_back(w_item_last);
for (int i = 0; i < components-1; i++)
window->DC.ItemWidthStack.push_back(w_item_one);
@@ -6201,7 +6038,7 @@ float ImGui::CalcItemWidth()
float region_max_x = GetContentRegionMaxAbs().x;
w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
}
- w = (float)(int)w;
+ w = IM_FLOOR(w);
return w;
}
@@ -6644,7 +6481,7 @@ void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond con
if (size.x > 0.0f)
{
window->AutoFitFramesX = 0;
- window->SizeFull.x = ImFloor(size.x);
+ window->SizeFull.x = IM_FLOOR(size.x);
}
else
{
@@ -6654,7 +6491,7 @@ void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond con
if (size.y > 0.0f)
{
window->AutoFitFramesY = 0;
- window->SizeFull.y = ImFloor(size.y);
+ window->SizeFull.y = IM_FLOOR(size.y);
}
else
{
@@ -6790,7 +6627,7 @@ ImVec2 ImGui::GetContentRegionMax()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- ImVec2 mx = window->ContentsRegionRect.Max - window->Pos;
+ ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
if (window->DC.CurrentColumns)
mx.x = window->WorkRect.Max.x - window->Pos.x;
return mx;
@@ -6801,7 +6638,7 @@ ImVec2 ImGui::GetContentRegionMaxAbs()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- ImVec2 mx = window->ContentsRegionRect.Max;
+ ImVec2 mx = window->ContentRegionRect.Max;
if (window->DC.CurrentColumns)
mx.x = window->WorkRect.Max.x;
return mx;
@@ -6817,19 +6654,19 @@ ImVec2 ImGui::GetContentRegionAvail()
ImVec2 ImGui::GetWindowContentRegionMin()
{
ImGuiWindow* window = GImGui->CurrentWindow;
- return window->ContentsRegionRect.Min - window->Pos;
+ return window->ContentRegionRect.Min - window->Pos;
}
ImVec2 ImGui::GetWindowContentRegionMax()
{
ImGuiWindow* window = GImGui->CurrentWindow;
- return window->ContentsRegionRect.Max - window->Pos;
+ return window->ContentRegionRect.Max - window->Pos;
}
float ImGui::GetWindowContentRegionWidth()
{
ImGuiWindow* window = GImGui->CurrentWindow;
- return window->ContentsRegionRect.GetWidth();
+ return window->ContentRegionRect.GetWidth();
}
float ImGui::GetTextLineHeight()
@@ -7109,7 +6946,7 @@ void ImGui::EndGroup()
}
window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
- ItemSize(group_bb.GetSize(), 0.0f);
+ ItemSize(group_bb.GetSize());
ItemAdd(group_bb, 0);
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
@@ -7183,6 +7020,54 @@ void ImGui::Unindent(float indent_w)
//-----------------------------------------------------------------------------
+// [SECTION] ERROR CHECKING
+//-----------------------------------------------------------------------------
+
+static void ImGui::ErrorCheckEndFrame()
+{
+ // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
+ // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
+ ImGuiContext& g = *GImGui;
+ if (g.CurrentWindowStack.Size != 1)
+ {
+ if (g.CurrentWindowStack.Size > 1)
+ {
+ IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
+ while (g.CurrentWindowStack.Size > 1)
+ End();
+ }
+ else
+ {
+ IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
+ }
+ }
+
+}
+
+// Save and compare stack sizes on Begin()/End() to detect usage errors
+// Begin() calls this with write=true
+// End() calls this with write=false
+static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write)
+{
+ ImGuiContext& g = *GImGui;
+ short* p = &window->DC.StackSizesBackup[0];
+
+ // Window stacks
+ // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
+ { int n = window->IDStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!"); p++; } // Too few or too many PopID()/TreePop()
+ { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup()
+
+ // Global stacks
+ // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
+ { int n = g.BeginPopupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup()
+ { int n = g.ColorModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor()
+ { int n = g.StyleModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar()
+ { int n = g.FontStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont()
+ IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
+}
+
+
+//-----------------------------------------------------------------------------
// [SECTION] SCROLLING
//-----------------------------------------------------------------------------
@@ -7306,7 +7191,7 @@ void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x
{
// We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
- window->ScrollTarget.x = (float)(int)(local_x + window->Scroll.x);
+ window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x);
window->ScrollTargetCenterRatio.x = center_x_ratio;
}
@@ -7316,7 +7201,7 @@ void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y
IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
local_y -= decoration_up_height;
- window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y);
+ window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y);
window->ScrollTargetCenterRatio.y = center_y_ratio;
}
@@ -7500,19 +7385,6 @@ void ImGui::OpenPopupEx(ImGuiID id)
}
}
-bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
-{
- ImGuiWindow* window = GImGui->CurrentWindow;
- if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
- {
- ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
- IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
- OpenPopupEx(id);
- return true;
- }
- return false;
-}
-
void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
{
ImGuiContext& g = *GImGui;
@@ -7673,13 +7545,32 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
void ImGui::EndPopup()
{
ImGuiContext& g = *GImGui;
- IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
+ ImGuiWindow* window = g.CurrentWindow;
+ IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
IM_ASSERT(g.BeginPopupStack.Size > 0);
// Make all menus and popups wrap around for now, may need to expose that policy.
- NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY);
+ NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
+ // Child-popups don't need to be layed out
+ IM_ASSERT(g.WithinEndChild == false);
+ if (window->Flags & ImGuiWindowFlags_ChildWindow)
+ g.WithinEndChild = true;
End();
+ g.WithinEndChild = false;
+}
+
+bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
+{
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
+ {
+ ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
+ IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
+ OpenPopupEx(id);
+ return true;
+ }
+ return false;
}
// This is a helper to handle the simplest case of associating one named popup to one given widget.
@@ -8170,6 +8061,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
init_for_nav = true;
+ //IMGUI_DEBUG_LOG("[Nav] NavInitWindow() init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
if (init_for_nav)
{
SetNavID(0, g.NavLayer);
@@ -8219,11 +8111,11 @@ float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input.
return (t == 0.0f) ? 1.0f : 0.0f;
if (mode == ImGuiInputReadMode_Repeat)
- return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f);
+ return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f);
if (mode == ImGuiInputReadMode_RepeatSlow)
- return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f);
+ return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
if (mode == ImGuiInputReadMode_RepeatFast)
- return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f);
+ return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
return 0.0f;
}
@@ -8269,7 +8161,6 @@ static void ImGui::NavUpdate()
NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
- NAV_MAP_KEY(ImGuiKey_Tab, ImGuiNavInput_KeyTab_ );
if (g.IO.KeyCtrl)
g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
if (g.IO.KeyShift)
@@ -8287,6 +8178,7 @@ static void ImGui::NavUpdate()
if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow)
{
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
+ //IMGUI_DEBUG_LOG("[Nav] Apply NavInitRequest result: 0x%08X Layer %d in \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
if (g.NavInitRequestFromMove)
SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
else
@@ -8343,11 +8235,11 @@ static void ImGui::NavUpdate()
g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
// Process NavCancel input (to close a popup, get back to parent, clear focus)
- if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
+ if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
{
if (g.ActiveId != 0)
{
- if (!(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_Cancel)))
+ if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
ClearActiveID();
}
else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
@@ -8387,14 +8279,14 @@ static void ImGui::NavUpdate()
if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
{
bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
- bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
+ bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
if (g.ActiveId == 0 && activate_pressed)
g.NavActivateId = g.NavId;
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
g.NavActivateDownId = g.NavId;
if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
g.NavActivatePressedId = g.NavId;
- if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
+ if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
g.NavInputId = g.NavId;
}
if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
@@ -8409,17 +8301,17 @@ static void ImGui::NavUpdate()
g.NavNextActivateId = 0;
// Initiate directional inputs request
- const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags;
if (g.NavMoveRequestForward == ImGuiNavForward_None)
{
g.NavMoveDir = ImGuiDir_None;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
- if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
+ if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
{
- if ((allowed_dir_flags & (1 << ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Left; }
- if ((allowed_dir_flags & (1 << ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Right; }
- if ((allowed_dir_flags & (1 << ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Up; }
- if ((allowed_dir_flags & (1 << ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Down; }
+ const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
+ if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
+ if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
+ if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
+ if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
}
g.NavMoveClipDir = g.NavMoveDir;
}
@@ -8436,7 +8328,7 @@ static void ImGui::NavUpdate()
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
float nav_scoring_rect_offset_y = 0.0f;
if (nav_keyboard_active)
- nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(allowed_dir_flags);
+ nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
// If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
if (g.NavMoveDir != ImGuiDir_None)
@@ -8446,6 +8338,7 @@ static void ImGui::NavUpdate()
}
if (g.NavMoveRequest && g.NavId == 0)
{
+ //IMGUI_DEBUG_LOG("[Nav] NavInitRequest from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
g.NavInitRequest = g.NavInitRequestFromMove = true;
g.NavInitResultId = 0;
g.NavDisableHighlight = false;
@@ -8457,7 +8350,7 @@ static void ImGui::NavUpdate()
{
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
ImGuiWindow* window = g.NavWindow;
- const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
+ const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * g.IO.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
{
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
@@ -8583,7 +8476,7 @@ static void ImGui::NavUpdateMoveResult()
}
// Handle PageUp/PageDown/Home/End keys
-static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
+static float ImGui::NavUpdatePageUpPageDown()
{
ImGuiContext& g = *GImGui;
if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
@@ -8592,10 +8485,10 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
return 0.0f;
ImGuiWindow* window = g.NavWindow;
- const bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
- const bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
- const bool home_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_Home]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
- const bool end_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_End]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
+ const bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
+ const bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
+ const bool home_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
+ const bool end_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
{
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
@@ -8713,7 +8606,7 @@ static void ImGui::NavUpdateWindowing()
}
// Start CTRL-TAB or Square+L/R window selection
- bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
+ bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
if (start_windowing_with_gamepad || start_windowing_with_keyboard)
if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
@@ -8732,7 +8625,7 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
// Select window to focus
- const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
+ const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
if (focus_change_dir != 0)
{
NavUpdateWindowingHighlightWindow(focus_change_dir);
@@ -8764,9 +8657,9 @@ static void ImGui::NavUpdateWindowing()
// Keyboard: Press and Release ALT to toggle menu layer
// 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
- if (IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
+ if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
g.NavWindowingToggleLayer = true;
- if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
+ if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
apply_toggle_layer = true;
@@ -9183,9 +9076,15 @@ void ImGui::LogText(const char* fmt, ...)
va_list args;
va_start(args, fmt);
if (g.LogFile)
- vfprintf(g.LogFile, fmt, args);
+ {
+ g.LogBuffer.Buf.resize(0);
+ g.LogBuffer.appendfv(fmt, args);
+ ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
+ }
else
+ {
g.LogBuffer.appendfv(fmt, args);
+ }
va_end(args);
}
@@ -9262,8 +9161,11 @@ void ImGui::LogToTTY(int auto_open_depth)
ImGuiContext& g = *GImGui;
if (g.LogEnabled)
return;
+ IM_UNUSED(auto_open_depth);
+#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
LogBegin(ImGuiLogType_TTY, auto_open_depth);
g.LogFile = stdout;
+#endif
}
// Start logging/capturing text output to given file
@@ -9280,8 +9182,8 @@ void ImGui::LogToFile(int auto_open_depth, const char* filename)
filename = g.IO.LogFilename;
if (!filename || !filename[0])
return;
- FILE* f = ImFileOpen(filename, "ab");
- if (f == NULL)
+ ImFileHandle f = ImFileOpen(filename, "ab");
+ if (!f)
{
IM_ASSERT(0);
return;
@@ -9318,10 +9220,12 @@ void ImGui::LogFinish()
switch (g.LogType)
{
case ImGuiLogType_TTY:
+#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
fflush(g.LogFile);
+#endif
break;
case ImGuiLogType_File:
- fclose(g.LogFile);
+ ImFileClose(g.LogFile);
break;
case ImGuiLogType_Buffer:
break;
@@ -9347,7 +9251,11 @@ void ImGui::LogButtons()
ImGuiContext& g = *GImGui;
PushID("LogButtons");
+#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
const bool log_to_tty = Button("Log To TTY"); SameLine();
+#else
+ const bool log_to_tty = false;
+#endif
const bool log_to_file = Button("Log To File"); SameLine();
const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
PushAllowKeyboardFocus(false);
@@ -9387,25 +9295,31 @@ void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
{
ImGuiContext& g = *GImGui;
- g.SettingsWindows.push_back(ImGuiWindowSettings());
- ImGuiWindowSettings* settings = &g.SettingsWindows.back();
+
#if !IMGUI_DEBUG_INI_SETTINGS
// Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
// Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
if (const char* p = strstr(name, "###"))
name = p;
#endif
- settings->Name = ImStrdup(name);
- settings->ID = ImHashStr(name);
+ const size_t name_len = strlen(name);
+
+ // Allocate chunk
+ const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
+ ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
+ IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
+ settings->ID = ImHashStr(name, name_len);
+ memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator
+
return settings;
}
ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
{
ImGuiContext& g = *GImGui;
- for (int i = 0; i != g.SettingsWindows.Size; i++)
- if (g.SettingsWindows[i].ID == id)
- return &g.SettingsWindows[i];
+ for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
+ if (settings->ID == id)
+ return settings;
return NULL;
}
@@ -9473,18 +9387,12 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
line_end[-1] = 0;
const char* name_end = line_end - 1;
const char* type_start = line + 1;
- char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']');
+ char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
if (!type_end || !name_start)
- {
- name_start = type_start; // Import legacy entries that have no type
- type_start = "Window";
- }
- else
- {
- *type_end = 0; // Overwrite first ']'
- name_start++; // Skip second '['
- }
+ continue;
+ *type_end = 0; // Overwrite first ']'
+ name_start++; // Skip second '['
entry_handler = FindSettingsHandler(type_start);
entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
}
@@ -9507,11 +9415,11 @@ void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
size_t ini_data_size = 0;
const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
- FILE* f = ImFileOpen(ini_filename, "wt");
+ ImFileHandle f = ImFileOpen(ini_filename, "wt");
if (!f)
return;
- fwrite(ini_data, sizeof(char), ini_data_size, f);
- fclose(f);
+ ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
+ ImFileClose(f);
}
// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
@@ -9531,7 +9439,7 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
return g.SettingsIniData.c_str();
}
-static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
+static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
{
ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name));
if (!settings)
@@ -9539,7 +9447,7 @@ static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*
return (void*)settings;
}
-static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
+static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
{
ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
int x, y;
@@ -9549,7 +9457,7 @@ static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*,
else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0);
}
-static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
+static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
{
// Gather data from windows that were active during this session
// (if a window wasn't opened in this session we preserve its settings)
@@ -9560,11 +9468,11 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
continue;
- ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID);
+ ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID);
if (!settings)
{
settings = ImGui::CreateNewWindowSettings(window->Name);
- window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
+ window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
}
IM_ASSERT(settings->ID == window->ID);
settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y);
@@ -9573,15 +9481,15 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
}
// Write to text buffer
- buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve
- for (int i = 0; i != g.SettingsWindows.Size; i++)
+ buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
+ for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
{
- const ImGuiWindowSettings* settings = &g.SettingsWindows[i];
- buf->appendf("[%s][%s]\n", handler->TypeName, settings->Name);
+ const char* settings_name = settings->GetName();
+ buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
buf->appendf("Collapsed=%d\n", settings->Collapsed);
- buf->appendf("\n");
+ buf->append("\n");
}
}
@@ -9613,6 +9521,10 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
#else
#include <windows.h>
#endif
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions
+#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
+#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
+#endif
#elif defined(__APPLE__)
#include <TargetConditionals.h>
#endif
@@ -9775,6 +9687,20 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
//-----------------------------------------------------------------------------
#ifndef IMGUI_DISABLE_METRICS_WINDOW
+// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
+static void MetricsHelpMarker(const char* desc)
+{
+ ImGui::TextDisabled("(?)");
+ if (ImGui::IsItemHovered())
+ {
+ ImGui::BeginTooltip();
+ ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
+ ImGui::TextUnformatted(desc);
+ ImGui::PopTextWrapPos();
+ ImGui::EndTooltip();
+ }
+}
+
void ImGui::ShowMetricsWindow(bool* p_open)
{
if (!ImGui::Begin("Dear ImGui Metrics", p_open))
@@ -9784,12 +9710,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
// State
- enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Contents, WRT_ContentsRegionRect, WRT_Count }; // Windows Rect Type
- const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" };
+ enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
+ const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" };
static bool show_windows_rects = false;
static int show_windows_rect_type = WRT_WorkRect;
static bool show_windows_begin_order = false;
- static bool show_drawcmd_clip_rects = true;
+ static bool show_drawcmd_details = true;
// Basic info
ImGuiContext& g = *GImGui;
@@ -9816,8 +9742,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
else if (rect_type == WRT_InnerRect) { return window->InnerRect; }
else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; }
else if (rect_type == WRT_WorkRect) { return window->WorkRect; }
- else if (rect_type == WRT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
- else if (rect_type == WRT_ContentsRegionRect) { return window->ContentsRegionRect; }
+ else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
+ else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; }
IM_ASSERT(0);
return ImRect();
}
@@ -9840,9 +9766,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return;
if (window && !window->WasActive)
- ImGui::Text("(Note: owning Window is inactive: DrawList is not being rendered!)");
+ ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
- int elem_offset = 0;
+ unsigned int elem_offset = 0;
for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
{
if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
@@ -9852,45 +9778,77 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
continue;
}
+
ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
char buf[300];
- ImFormatString(buf, IM_ARRAYSIZE(buf), "Draw %4d triangles, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
- pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
+ ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd: %4d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
+ pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId,
+ pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
- if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered())
+ if (show_drawcmd_details && fg_draw_list && ImGui::IsItemHovered())
{
ImRect clip_rect = pcmd->ClipRect;
ImRect vtxs_rect;
- for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
+ for (unsigned int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
- clip_rect.Floor(); fg_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,0,255,255));
- vtxs_rect.Floor(); fg_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,255,0,255));
+ fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255,0,255,255));
+ fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(255,255,0,255));
}
if (!pcmd_node_open)
continue;
+ // Calculate approximate coverage area (touched pixel count)
+ // This will be in pixels squared as long there's no post-scaling happening to the renderer output.
+ float total_area = 0.0f;
+ for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3)
+ {
+ ImVec2 triangle[3];
+ for (int n = 0; n < 3; n++)
+ triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
+ total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
+ }
+
+ // Display vertex information summary. Hover to get all triangles drawn in wire-frame
+ ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
+ ImGui::Selectable(buf);
+ if (fg_draw_list && ImGui::IsItemHovered() && show_drawcmd_details)
+ {
+ // Draw wire-frame version of everything
+ ImDrawListFlags backup_flags = fg_draw_list->Flags;
+ fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
+ ImRect clip_rect = pcmd->ClipRect;
+ fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255));
+ for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3)
+ {
+ ImVec2 triangle[3];
+ for (int n = 0; n < 3; n++)
+ triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
+ fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f);
+ }
+ fg_draw_list->Flags = backup_flags;
+ }
+
// Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
- ImGui::Text("ElemCount: %d, ElemCount/3: %d, VtxOffset: +%d, IdxOffset: +%d", pcmd->ElemCount, pcmd->ElemCount/3, pcmd->VtxOffset, pcmd->IdxOffset);
ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
while (clipper.Step())
for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
{
char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
- ImVec2 triangles_pos[3];
+ ImVec2 triangle[3];
for (int n = 0; n < 3; n++, idx_i++)
{
- int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i;
- ImDrawVert& v = draw_list->VtxBuffer[vtx_i];
- triangles_pos[n] = v.pos;
+ ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
+ triangle[n] = v.pos;
buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
- (n == 0) ? "elem" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
+ (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
}
+
ImGui::Selectable(buf, false);
if (fg_draw_list && ImGui::IsItemHovered())
{
ImDrawListFlags backup_flags = fg_draw_list->Flags;
- fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles.
- fg_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f);
+ fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
+ fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f);
fg_draw_list->Flags = backup_flags;
}
}
@@ -9925,7 +9883,10 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::BulletText("%s: NULL", label);
return;
}
- if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window))
+ bool open = ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window);
+ if (ImGui::IsItemHovered() && window->WasActive)
+ ImGui::GetForegroundDrawList()->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
+ if (!open)
return;
ImGuiWindowFlags flags = window->Flags;
NodeDrawList(window, window->DrawList, "DrawList");
@@ -9934,7 +9895,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
(flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
(flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
(flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
- ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y);
+ ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
@@ -9952,7 +9913,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
NodeColumns(&window->ColumnsStorage[n]);
ImGui::TreePop();
}
- ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.size_in_bytes());
+ NodeStorage(&window->StateStorage, "Storage");
ImGui::TreePop();
}
@@ -9971,16 +9932,28 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::PushID(tab);
if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine();
- ImGui::Text("%02d%c Tab 0x%08X", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID);
+ ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "");
ImGui::PopID();
}
ImGui::TreePop();
}
}
+
+ static void NodeStorage(ImGuiStorage* storage, const char* label)
+ {
+ if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
+ return;
+ for (int n = 0; n < storage->Data.Size; n++)
+ {
+ const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
+ ImGui::BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
+ }
+ ImGui::TreePop();
+ }
};
Funcs::NodeWindows(g.Windows, "Windows");
- if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
+ if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
{
for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
@@ -9997,9 +9970,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::TreePop();
}
- if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size))
+ if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
{
- for (int n = 0; n < g.TabBars.Data.Size; n++)
+ for (int n = 0; n < g.TabBars.GetSize(); n++)
Funcs::NodeTabBar(g.TabBars.GetByIndex(n));
ImGui::TreePop();
}
@@ -10012,7 +9985,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
#endif
#if 0
- if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.Data.Size))
+ if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
{
ImGui::TreePop();
}
@@ -10043,6 +10016,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
if (ImGui::Button("Item Picker.."))
ImGui::DebugStartItemPicker();
+ ImGui::SameLine();
+ MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
ImGui::Checkbox("Show windows begin order", &show_windows_begin_order);
ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
@@ -10060,7 +10035,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
ImGui::Unindent();
}
- ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects);
+ ImGui::Checkbox("Show details when hovering ImDrawCmd node", &show_drawcmd_details);
ImGui::TreePop();
}
diff --git a/imgui/imgui.h b/imgui/imgui.h
index 9697c80d..9fcdaeaa 100644
--- a/imgui/imgui.h
+++ b/imgui/imgui.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.73
+// dear imgui, v1.74
// (headers)
// See imgui.cpp file for documentation.
@@ -27,7 +27,7 @@ Index of this file:
#pragma once
-// Configuration file with compile-time options (edit imconfig.h or define IMGUI_USER_CONFIG to your own filename)
+// Configuration file with compile-time options (edit imconfig.h or #define IMGUI_USER_CONFIG to your own filename)
#ifdef IMGUI_USER_CONFIG
#include IMGUI_USER_CONFIG
#endif
@@ -39,15 +39,16 @@ Index of this file:
// Header mess
//-----------------------------------------------------------------------------
-#include <float.h> // FLT_MAX
-#include <stdarg.h> // va_list
+// Includes
+#include <float.h> // FLT_MIN, FLT_MAX
+#include <stdarg.h> // va_list, va_start, va_end
#include <stddef.h> // ptrdiff_t, NULL
#include <string.h> // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp
// Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
-#define IMGUI_VERSION "1.73"
-#define IMGUI_VERSION_NUM 17300
+#define IMGUI_VERSION "1.74"
+#define IMGUI_VERSION_NUM 17400
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
@@ -66,19 +67,21 @@ Index of this file:
#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h
#endif
#if defined(__clang__) || defined(__GNUC__)
-#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to user functions.
+#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // To apply printf-style warnings to our functions.
#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0)))
#else
#define IM_FMTARGS(FMT)
#define IM_FMTLIST(FMT)
#endif
-#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers!
+#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers!
#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds.
#if (__cplusplus >= 201100)
#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11
#else
#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro.
#endif
+#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Last Unicode code point supported by this build.
+#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Standard invalid Unicode code point.
// Warnings
#if defined(__clang__)
@@ -123,7 +126,7 @@ struct ImGuiTextBuffer; // Helper to hold and append into a text buf
struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbb][,ccccc]")
// Typedefs and Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file)
-// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
+// Use your programming IDE "Go to definition" facility on the names in the central column below to find the actual flags/enum lists.
#ifndef ImTextureID
typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp)
#endif
@@ -157,7 +160,7 @@ typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData *data);
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data);
// Scalar data types
-typedef signed char ImS8; // 8-bit signed integer == char
+typedef signed char ImS8; // 8-bit signed integer
typedef unsigned char ImU8; // 8-bit unsigned integer
typedef signed short ImS16; // 16-bit signed integer
typedef unsigned short ImU16; // 16-bit unsigned integer
@@ -201,14 +204,14 @@ struct ImVec4
//-----------------------------------------------------------------------------
// ImGui: Dear ImGui end-user API
-// (Inside a namespace so you can add extra functions in your own separate file. Please don't modify imgui.cpp/.h!)
+// (Inside a namespace so you can add extra functions in your own separate file. Please don't modify imgui source files!)
//-----------------------------------------------------------------------------
namespace ImGui
{
// Context creation and access
// Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts.
- // All those functions are not reliant on the current context.
+ // None of those functions is reliant on the current context.
IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL);
IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context
IMGUI_API ImGuiContext* GetCurrentContext();
@@ -245,8 +248,9 @@ namespace ImGui
// which clicking will set the boolean to false when clicked.
// - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting
// anything to the window. Always call a matching End() for each Begin() call, regardless of its return value!
- // [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc.
- // where the EndXXX call should only be called if the corresponding BeginXXX function returned true.]
+ // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu,
+ // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function
+ // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.]
// - Note that the bottom of window stack always contains a window called "Debug".
IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
IMGUI_API void End();
@@ -255,13 +259,13 @@ namespace ImGui
// - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child.
// - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400).
// - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window.
- // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [this is due to legacy reason and is inconsistent with most other functions such as BeginMenu/EndMenu, BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function returned true.]
+ // Always call a matching EndChild() for each BeginChild() call, regardless of its return value [as with Begin: this is due to legacy reason and inconsistent with most BeginXXX functions apart from the regular Begin() which behaves like BeginChild().]
IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0);
IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags flags = 0);
IMGUI_API void EndChild();
// Windows Utilities
- // - "current window" = the window we are appending into while inside a Begin()/End() block. "next window" = next window we will Begin() into.
+ // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into.
IMGUI_API bool IsWindowAppearing();
IMGUI_API bool IsWindowCollapsed();
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options.
@@ -342,6 +346,7 @@ namespace ImGui
// Cursor / Layout
// - By "cursor" we mean the current output position.
// - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down.
+ // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceeding widget.
IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator.
IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates.
IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context.
@@ -383,8 +388,8 @@ namespace ImGui
IMGUI_API ImGuiID GetID(const void* ptr_id);
// Widgets: Text
- IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.
- IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // simple formatted text
+ IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.
+ IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text
IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1);
IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor();
IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2);
@@ -399,6 +404,7 @@ namespace ImGui
// Widgets: Main
// - Most widgets return true when the value has been changed or when pressed/selected
+ // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state.
IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0)); // button
IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text
IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); // button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.)
@@ -413,7 +419,7 @@ namespace ImGui
IMGUI_API void Bullet(); // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses
// Widgets: Combo Box
- // - The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items.
+ // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items.
// - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose.
IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);
IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true!
@@ -438,8 +444,8 @@ namespace ImGui
IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d");
IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d");
IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL);
- IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f);
- IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min = NULL, const void* v_max = NULL, const char* format = NULL, float power = 1.0f);
+ IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f);
+ IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, float power = 1.0f);
// Widgets: Sliders
// - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
@@ -453,11 +459,11 @@ namespace ImGui
IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d");
IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d");
IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d");
- IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f);
- IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f);
+ IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f);
+ IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f);
IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d");
- IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f);
+ IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, float power = 1.0f);
// Widgets: Input with Keyboard
// - If you want to use InputText() with a dynamic string type such as std::string or your own, see misc/cpp/imgui_stdlib.h
@@ -474,8 +480,8 @@ namespace ImGui
IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0);
IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0);
IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0);
- IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
- IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step = NULL, const void* step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
+ IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
// Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.)
// - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible.
@@ -509,7 +515,7 @@ namespace ImGui
// Widgets: Selectables
// - A selectable highlights when hovered, and can display another color when selected.
- // - Neighbors selectable extend their highlight bounds in order to leave no gap between them.
+ // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous.
IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper.
@@ -535,16 +541,19 @@ namespace ImGui
IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL);
// Widgets: Menus
- IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar.
- IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true!
+ // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar.
+ // - Use BeginMainMenuBar() to create a menu bar at the top of the screen.
IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window).
IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true!
+ IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar.
+ IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true!
IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true!
IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true!
IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment
IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL
// Tooltips
+ // - Tooltip are windows following the mouse which do not take focus away.
IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items).
IMGUI_API void EndTooltip();
IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip().
@@ -556,7 +565,7 @@ namespace ImGui
// - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
// - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls.
// User can manipulate the visibility state by calling OpenPopup().
- // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
+ // (*) You can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
// Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time.
IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true!
@@ -572,6 +581,7 @@ namespace ImGui
// Columns
// - You can also use SameLine(pos_x) to mimic simplified columns.
// - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!)
+ // - By end of the 2019 we will expose a new 'Table' api which will replace columns.
IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true);
IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished
IMGUI_API int GetColumnIndex(); // get current column index
@@ -582,7 +592,6 @@ namespace ImGui
IMGUI_API int GetColumnsCount();
// Tab Bars, Tabs
- // [BETA API] API may evolve!
IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar
IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true!
IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0);// create a Tab. Returns true if the Tab is selected.
@@ -629,6 +638,7 @@ namespace ImGui
IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive).
IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing.
IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item).
+ IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode().
IMGUI_API bool IsAnyItemHovered(); // is any item hovered?
IMGUI_API bool IsAnyItemActive(); // is any item active?
IMGUI_API bool IsAnyItemFocused(); // is any item focused?
@@ -950,12 +960,12 @@ enum ImGuiKey_
ImGuiKey_Enter,
ImGuiKey_Escape,
ImGuiKey_KeyPadEnter,
- ImGuiKey_A, // for text edit CTRL+A: select all
- ImGuiKey_C, // for text edit CTRL+C: copy
- ImGuiKey_V, // for text edit CTRL+V: paste
- ImGuiKey_X, // for text edit CTRL+X: cut
- ImGuiKey_Y, // for text edit CTRL+Y: redo
- ImGuiKey_Z, // for text edit CTRL+Z: undo
+ ImGuiKey_A, // for text edit CTRL+A: select all
+ ImGuiKey_C, // for text edit CTRL+C: copy
+ ImGuiKey_V, // for text edit CTRL+V: paste
+ ImGuiKey_X, // for text edit CTRL+X: cut
+ ImGuiKey_Y, // for text edit CTRL+Y: redo
+ ImGuiKey_Z, // for text edit CTRL+Z: undo
ImGuiKey_COUNT
};
@@ -986,7 +996,6 @@ enum ImGuiNavInput_
// [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them.
// Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[].
ImGuiNavInput_KeyMenu_, // toggle menu // = io.KeyAlt
- ImGuiNavInput_KeyTab_, // tab // = Tab key
ImGuiNavInput_KeyLeft_, // move left // = Arrow keys
ImGuiNavInput_KeyRight_, // move right
ImGuiNavInput_KeyUp_, // move up
@@ -1018,7 +1027,7 @@ enum ImGuiBackendFlags_
ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end Platform supports gamepad and currently has one connected.
ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end Platform supports honoring GetMouseCursor() value to change the OS cursor shape.
ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Back-end Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set).
- ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bits indices.
+ ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices.
};
// Enumeration for PushStyleColor() / PopStyleColor()
@@ -1217,10 +1226,12 @@ template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p
//-----------------------------------------------------------------------------
// Helper: ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
-// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
-// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.
-// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,
-// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
+//-----------------------------------------------------------------------------
+// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it.
+// - We use std-like naming convention here, which is a little unusual for this codebase.
+// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.
+// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,
+// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
//-----------------------------------------------------------------------------
template<typename T>
@@ -1262,6 +1273,7 @@ struct ImVector
inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
+ inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; }
inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }
// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
@@ -1277,7 +1289,7 @@ struct ImVector
inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; }
inline bool find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; }
inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; }
- inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; }
+ inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; }
};
//-----------------------------------------------------------------------------
@@ -1572,11 +1584,6 @@ namespace ImGui
static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); }
static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); }
static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); }
- // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)
- IMGUI_API bool Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // Use SetNextWindowSize(size, ImGuiCond_FirstUseEver) + SetNextWindowBgAlpha() instead.
- static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); }
- static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); }
- static inline void SetNextWindowPosCenter(ImGuiCond c=0) { ImGuiIO& io = GetIO(); SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), c, ImVec2(0.5f, 0.5f)); }
}
typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent
typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData;
@@ -1629,11 +1636,11 @@ struct ImGuiTextBuffer
IMGUI_API static char EmptyString[1];
ImGuiTextBuffer() { }
- inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }
+ inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }
const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; }
const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator
int size() const { return Buf.Size ? Buf.Size - 1 : 0; }
- bool empty() { return Buf.Size <= 1; }
+ bool empty() const { return Buf.Size <= 1; }
void clear() { Buf.clear(); }
void reserve(int capacity) { Buf.reserve(capacity); }
const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; }
@@ -1723,7 +1730,7 @@ struct ImGuiListClipper
IMGUI_API void End(); // Automatically called on the last call of Step() that returns false.
};
-// Helpers macros to generate 32-bits encoded colors
+// Helpers macros to generate 32-bit encoded colors
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
#define IM_COL32_R_SHIFT 16
#define IM_COL32_G_SHIFT 8
@@ -1787,13 +1794,13 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c
// Typically, 1 command = 1 GPU draw call (unless command is a callback)
// Pre 1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset'
-// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bits indices.
+// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices.
struct ImDrawCmd
{
unsigned int ElemCount; // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[].
ImVec4 ClipRect; // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates
ImTextureID TextureId; // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.
- unsigned int VtxOffset; // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bits indices.
+ unsigned int VtxOffset; // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bit indices.
unsigned int IdxOffset; // Start offset in index buffer. Always equal to sum of ElemCount drawn so far.
ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
void* UserCallbackData; // The draw callback code can access this.
@@ -1802,8 +1809,8 @@ struct ImDrawCmd
};
// Vertex index
-// (to allow large meshes with 16-bits indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end)
-// (to use 32-bits indices: override with '#define ImDrawIdx unsigned int' in imconfig.h)
+// (to allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end)
+// (to use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h)
#ifndef ImDrawIdx
typedef unsigned short ImDrawIdx;
#endif
@@ -1912,7 +1919,7 @@ struct ImDrawList
// Primitives
// - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners.
IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f);
- IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4-bits corresponding to which corner to round
+ IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4 bits corresponding to which corner to round
IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // a: upper-left, b: lower-right (== upper-left + size)
IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left);
IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f);
@@ -2041,7 +2048,7 @@ struct ImFontGlyphRangesBuilder
ImVector<ImU32> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
ImFontGlyphRangesBuilder() { Clear(); }
- inline void Clear() { int size_in_bytes = 0x10000 / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); }
+ inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX+1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); }
inline bool GetBit(int n) const { int off = (n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
inline void SetBit(int n) { int off = (n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
inline void AddChar(ImWchar c) { SetBit(c); } // Add character
@@ -2053,12 +2060,12 @@ struct ImFontGlyphRangesBuilder
// See ImFontAtlas::AddCustomRectXXX functions.
struct ImFontAtlasCustomRect
{
- unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data.
+ unsigned int ID; // Input // User ID. Use < 0x110000 to map into a font glyph, >= 0x110000 for other/internal/custom texture data.
unsigned short Width, Height; // Input // Desired rectangle dimension
unsigned short X, Y; // Output // Packed position in Atlas
- float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance
- ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset
- ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font
+ float GlyphAdvanceX; // Input // For custom font glyphs only (ID < 0x110000): glyph xadvance
+ ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID < 0x110000): glyph display offset
+ ImFont* Font; // Input // For custom font glyphs only (ID < 0x110000): target font
ImFontAtlasCustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; }
bool IsPacked() const { return X != 0xFFFF; }
};
@@ -2110,7 +2117,7 @@ struct ImFontAtlas
IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions.
IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel
IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel
- bool IsBuilt() { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); }
+ bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); }
void SetTexID(ImTextureID id) { TexID = id; }
//-------------------------------------------
@@ -2137,13 +2144,13 @@ struct ImFontAtlas
// After calling Build(), you can query the rectangle position and render your pixels.
// You can also request your rectangles to be mapped as font glyph (given a font + Unicode point),
// so you can render e.g. custom colorful icons and use them as regular glyphs.
- // Read misc/fonts/README.txt for more details about using colorful icons.
- IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
- IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font.
+ // Read docs/FONTS.txt for more details about using colorful icons.
+ IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x110000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
+ IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x110000 to register a rectangle to map into a specific font.
const ImFontAtlasCustomRect*GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; }
// [Internal]
- IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max);
+ IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const;
IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
//-------------------------------------------
@@ -2224,10 +2231,6 @@ struct ImFont
IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
IMGUI_API void SetFallbackChar(ImWchar c);
-
-#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- typedef ImFontGlyph Glyph; // OBSOLETED in 1.52+
-#endif
};
#if defined(__clang__)
diff --git a/imgui/imgui_demo.cpp b/imgui/imgui_demo.cpp
index ec1ada82..7e475992 100644
--- a/imgui/imgui_demo.cpp
+++ b/imgui/imgui_demo.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.73
+// dear imgui, v1.74
// (demo code)
// Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
@@ -100,12 +100,17 @@ Index of this file:
// Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n.
#ifdef _WIN32
#define IM_NEWLINE "\r\n"
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
#else
#define IM_NEWLINE "\n"
#endif
+#if defined(_MSC_VER) && !defined(snprintf)
+#define snprintf _snprintf
+#endif
+#if defined(_MSC_VER) && !defined(vsnprintf)
+#define vsnprintf _vsnprintf
+#endif
+
//-----------------------------------------------------------------------------
// [SECTION] Forward Declarations, Helpers
//-----------------------------------------------------------------------------
@@ -132,7 +137,7 @@ static void ShowExampleAppCustomRendering(bool* p_open);
static void ShowExampleMenuFile();
// Helper to display a little (?) mark which shows a tooltip when hovered.
-// In your own code you may want to display an actual icon if you are using a merged icon fonts (see misc/fonts/README.txt)
+// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.txt)
static void HelpMarker(const char* desc)
{
ImGui::TextDisabled("(?)");
@@ -152,25 +157,28 @@ void ImGui::ShowUserGuide()
ImGuiIO& io = ImGui::GetIO();
ImGui::BulletText("Double-click on title bar to collapse window.");
ImGui::BulletText("Click and drag on lower corner to resize window\n(double-click to auto fit window to its contents).");
- if (io.ConfigWindowsMoveFromTitleBarOnly)
- ImGui::BulletText("Click and drag on title bar to move window.");
- else
- ImGui::BulletText("Click and drag on any empty space to move window.");
- ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
+ ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
if (io.FontAllowUserScaling)
ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
- ImGui::BulletText("Mouse Wheel to scroll.");
- ImGui::BulletText("While editing text:\n");
+ ImGui::BulletText("While inputing text:\n");
ImGui::Indent();
- ImGui::BulletText("Hold SHIFT or use mouse to select text.");
ImGui::BulletText("CTRL+Left/Right to word jump.");
ImGui::BulletText("CTRL+A or double-click to select all.");
- ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard.");
+ ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
ImGui::BulletText("ESCAPE to revert.");
ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
ImGui::Unindent();
+ ImGui::BulletText("With keyboard navigation enabled:");
+ ImGui::Indent();
+ ImGui::BulletText("Arrow keys to navigate.");
+ ImGui::BulletText("Space to activate a widget.");
+ ImGui::BulletText("Return to input text into a widget.");
+ ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
+ ImGui::BulletText("Alt to jump to the menu layer of a window.");
+ ImGui::BulletText("CTRL+Tab to select a window.");
+ ImGui::Unindent();
}
//-----------------------------------------------------------------------------
@@ -311,12 +319,20 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (ImGui::CollapsingHeader("Help"))
{
+ ImGui::Text("ABOUT THIS DEMO:");
+ ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
+ ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
+ ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
+ "and Metrics (general purpose Dear ImGui debugging tool).");
+ ImGui::Separator();
+
ImGui::Text("PROGRAMMER GUIDE:");
- ImGui::BulletText("Please see the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
- ImGui::BulletText("Please see the comments in imgui.cpp.");
- ImGui::BulletText("Please see the examples/ application.");
- ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
- ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
+ ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
+ ImGui::BulletText("See comments in imgui.cpp.");
+ ImGui::BulletText("See example applications in the examples/ folder.");
+ ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/");
+ ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
+ ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
ImGui::Separator();
ImGui::Text("USER GUIDE:");
@@ -360,7 +376,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (ImGui::TreeNode("Backend Flags"))
{
- HelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.");
+ HelpMarker("Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\nHere we expose then as read-only fields to avoid breaking interactions with your back-end.");
ImGuiBackendFlags backend_flags = io.BackendFlags; // Make a local copy to avoid modifying actual back-end flags.
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors);
@@ -372,6 +388,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (ImGui::TreeNode("Style"))
{
+ HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
ImGui::ShowStyleEditor();
ImGui::TreePop();
ImGui::Separator();
@@ -753,14 +770,14 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("UTF-8 Text"))
{
// UTF-8 test with Japanese characters
- // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read misc/fonts/README.txt for details.)
+ // (Needs a suitable font, try Noto, or Arial Unicode, or M+ fonts. Read docs/FONTS.txt for details.)
// - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
// - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature')
// - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE.
// Instead we are encoding a few strings with hexadecimal constants. Don't do this in your application!
// Please use u8"text in any language" in your application!
// Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application.
- ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read misc/fonts/README.txt for details.");
+ ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. Read docs/FONTS.txt for details.");
ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string.
ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
@@ -923,7 +940,7 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("In columns"))
{
ImGui::Columns(3, NULL, false);
- static bool selected[16] = { 0 };
+ static bool selected[16] = {};
for (int i = 0; i < 16; i++)
{
char label[32]; sprintf(label, "Item %d", i);
@@ -1075,7 +1092,7 @@ static void ShowDemoWindowWidgets()
// Create a dummy array of contiguous float values to plot
// Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter.
- static float values[90] = { 0 };
+ static float values[90] = {};
static int values_offset = 0;
static double refresh_time = 0.0;
if (!animate || refresh_time == 0.0)
@@ -1176,7 +1193,7 @@ static void ShowDemoWindowWidgets()
// Generate a dummy default palette. The palette will persist and can be edited.
static bool saved_palette_init = true;
- static ImVec4 saved_palette[32] = { };
+ static ImVec4 saved_palette[32] = {};
if (saved_palette_init)
{
for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
@@ -1506,24 +1523,21 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Drag and Drop"))
{
+ if (ImGui::TreeNode("Drag and drop in standard widgets"))
{
// ColorEdit widgets automatically act as drag source and drag target.
// They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F to allow your own widgets
// to use colors in their drag and drop interaction. Also see the demo in Color Picker -> Palette demo.
- ImGui::BulletText("Drag and drop in standard widgets");
- ImGui::SameLine();
HelpMarker("You can drag from the colored squares.");
- ImGui::Indent();
- static float col1[3] = { 1.0f,0.0f,0.2f };
- static float col2[4] = { 0.4f,0.7f,0.0f,0.5f };
+ static float col1[3] = { 1.0f, 0.0f, 0.2f };
+ static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
ImGui::ColorEdit3("color 1", col1);
ImGui::ColorEdit4("color 2", col2);
- ImGui::Unindent();
+ ImGui::TreePop();
}
+ if (ImGui::TreeNode("Drag and drop to copy/swap items"))
{
- ImGui::BulletText("Drag and drop to copy/swap items");
- ImGui::Indent();
enum Mode
{
Mode_Copy,
@@ -1577,7 +1591,31 @@ static void ShowDemoWindowWidgets()
}
ImGui::PopID();
}
- ImGui::Unindent();
+ ImGui::TreePop();
+ }
+
+ if (ImGui::TreeNode("Drag to reorder items (simple)"))
+ {
+ // Simple reordering
+ HelpMarker("We don't use the drag and drop api at all here! Instead we query when the item is held but not hovered, and order items accordingly.");
+ static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
+ for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
+ {
+ const char* item = item_names[n];
+ ImGui::Selectable(item);
+
+ if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
+ {
+ int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
+ if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
+ {
+ item_names[n] = item_names[n_next];
+ item_names[n_next] = item;
+ ImGui::ResetMouseDragDelta();
+ }
+ }
+ }
+ ImGui::TreePop();
}
ImGui::TreePop();
@@ -1587,7 +1625,7 @@ static void ShowDemoWindowWidgets()
{
// Submit an item (various types available) so we can query their status in the following block.
static int item_type = 1;
- ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode (w/ double-click)\0ListBox\0");
+ ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode\0TreeNode (w/ double-click)\0ListBox\0", 20);
ImGui::SameLine();
HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions.");
bool ret = false;
@@ -1604,13 +1642,14 @@ static void ShowDemoWindowWidgets()
if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
- if (item_type == 10){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
- if (item_type == 11){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
+ if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
+ if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
+ if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
- // Display the value of IsItemHovered() and other common item state functions.
+ // Display the value of IsItemHovered() and other common item state functions.
// Note that the ImGuiHoveredFlags_XXX flags can be combined.
- // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
- // we query every state in a single call to avoid storing them and to simplify the code
+ // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
+ // we query every state in a single call to avoid storing them and to simplify the code
ImGui::BulletText(
"Return value = %d\n"
"IsItemFocused() = %d\n"
@@ -1626,6 +1665,7 @@ static void ShowDemoWindowWidgets()
"IsItemDeactivatedAfterEdit() = %d\n"
"IsItemVisible() = %d\n"
"IsItemClicked() = %d\n"
+ "IsItemToggledOpen() = %d\n"
"GetItemRectMin() = (%.1f, %.1f)\n"
"GetItemRectMax() = (%.1f, %.1f)\n"
"GetItemRectSize() = (%.1f, %.1f)",
@@ -1643,6 +1683,7 @@ static void ShowDemoWindowWidgets()
ImGui::IsItemDeactivatedAfterEdit(),
ImGui::IsItemVisible(),
ImGui::IsItemClicked(),
+ ImGui::IsItemToggledOpen(),
ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
@@ -1653,7 +1694,7 @@ static void ShowDemoWindowWidgets()
if (embed_all_inside_a_child_window)
ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20), true);
- // Testing IsWindowFocused() function with its various flags.
+ // Testing IsWindowFocused() function with its various flags.
// Note that the ImGuiFocusedFlags_XXX flags can be combined.
ImGui::BulletText(
"IsWindowFocused() = %d\n"
@@ -2047,55 +2088,99 @@ static void ShowDemoWindowLayout()
if (ImGui::TreeNode("Text Baseline Alignment"))
{
- HelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets.");
-
- ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
- ImGui::Text("Hello\nWorld"); ImGui::SameLine();
- ImGui::Text("Banana");
-
- ImGui::Text("Banana"); ImGui::SameLine();
- ImGui::Text("Hello\nWorld"); ImGui::SameLine();
- ImGui::Text("One\nTwo\nThree");
-
- ImGui::Button("HOP##1"); ImGui::SameLine();
- ImGui::Text("Banana"); ImGui::SameLine();
- ImGui::Text("Hello\nWorld"); ImGui::SameLine();
- ImGui::Text("Banana");
-
- ImGui::Button("HOP##2"); ImGui::SameLine();
- ImGui::Text("Hello\nWorld"); ImGui::SameLine();
- ImGui::Text("Banana");
-
- ImGui::Button("TEST##1"); ImGui::SameLine();
- ImGui::Text("TEST"); ImGui::SameLine();
- ImGui::SmallButton("TEST##2");
-
- ImGui::AlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets.
- ImGui::Text("Text aligned to Widget"); ImGui::SameLine();
- ImGui::Button("Widget##1"); ImGui::SameLine();
- ImGui::Text("Widget"); ImGui::SameLine();
- ImGui::SmallButton("Widget##2"); ImGui::SameLine();
- ImGui::Button("Widget##3");
-
- // Tree
- const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
- ImGui::Button("Button##1");
- ImGui::SameLine(0.0f, spacing);
- if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data
+ {
+ ImGui::BulletText("Text baseline:");
+ ImGui::SameLine();
+ HelpMarker("This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets.");
+ ImGui::Indent();
- ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit).
- bool node_open = ImGui::TreeNode("Node##2"); // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content.
- ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
- if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data
+ ImGui::Text("KO Blahblah"); ImGui::SameLine();
+ ImGui::Button("Some framed item"); ImGui::SameLine();
+ HelpMarker("Baseline of button will look misaligned with text..");
- // Bullet
- ImGui::Button("Button##3");
- ImGui::SameLine(0.0f, spacing);
- ImGui::BulletText("Bullet text");
+ // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
+ // Because we don't know what's coming after the Text() statement, we need to move the text baseline down by FramePadding.y
+ ImGui::AlignTextToFramePadding();
+ ImGui::Text("OK Blahblah"); ImGui::SameLine();
+ ImGui::Button("Some framed item"); ImGui::SameLine();
+ HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
- ImGui::AlignTextToFramePadding();
- ImGui::BulletText("Node");
- ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
+ // SmallButton() uses the same vertical padding as Text
+ ImGui::Button("TEST##1"); ImGui::SameLine();
+ ImGui::Text("TEST"); ImGui::SameLine();
+ ImGui::SmallButton("TEST##2");
+
+ // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
+ ImGui::AlignTextToFramePadding();
+ ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
+ ImGui::Button("Item##1"); ImGui::SameLine();
+ ImGui::Text("Item"); ImGui::SameLine();
+ ImGui::SmallButton("Item##2"); ImGui::SameLine();
+ ImGui::Button("Item##3");
+
+ ImGui::Unindent();
+ }
+
+ ImGui::Spacing();
+
+ {
+ ImGui::BulletText("Multi-line text:");
+ ImGui::Indent();
+ ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
+ ImGui::Text("Hello\nWorld"); ImGui::SameLine();
+ ImGui::Text("Banana");
+
+ ImGui::Text("Banana"); ImGui::SameLine();
+ ImGui::Text("Hello\nWorld"); ImGui::SameLine();
+ ImGui::Text("One\nTwo\nThree");
+
+ ImGui::Button("HOP##1"); ImGui::SameLine();
+ ImGui::Text("Banana"); ImGui::SameLine();
+ ImGui::Text("Hello\nWorld"); ImGui::SameLine();
+ ImGui::Text("Banana");
+
+ ImGui::Button("HOP##2"); ImGui::SameLine();
+ ImGui::Text("Hello\nWorld"); ImGui::SameLine();
+ ImGui::Text("Banana");
+ ImGui::Unindent();
+ }
+
+ ImGui::Spacing();
+
+ {
+ ImGui::BulletText("Misc items:");
+ ImGui::Indent();
+
+ // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button
+ ImGui::Button("80x80", ImVec2(80, 80));
+ ImGui::SameLine();
+ ImGui::Button("50x50", ImVec2(50, 50));
+ ImGui::SameLine();
+ ImGui::Button("Button()");
+ ImGui::SameLine();
+ ImGui::SmallButton("SmallButton()");
+
+ // Tree
+ const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
+ ImGui::Button("Button##1");
+ ImGui::SameLine(0.0f, spacing);
+ if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data
+
+ ImGui::AlignTextToFramePadding(); // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit).
+ bool node_open = ImGui::TreeNode("Node##2");// Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content.
+ ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
+ if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); } // Dummy tree data
+
+ // Bullet
+ ImGui::Button("Button##3");
+ ImGui::SameLine(0.0f, spacing);
+ ImGui::BulletText("Bullet text");
+
+ ImGui::AlignTextToFramePadding();
+ ImGui::BulletText("Node");
+ ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
+ ImGui::Unindent();
+ }
ImGui::TreePop();
}
@@ -2142,7 +2227,7 @@ static void ShowDemoWindowLayout()
ImGui::TextUnformatted(names[i]);
ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
- ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags);
+ bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags);
if (ImGui::BeginMenuBar())
{
ImGui::TextUnformatted("abc");
@@ -2152,16 +2237,19 @@ static void ShowDemoWindowLayout()
ImGui::SetScrollY(scroll_to_off_px);
if (scroll_to_pos)
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
- for (int item = 0; item < 100; item++)
+ if (window_visible) // Avoid calling SetScrollHereY when running with culled items
{
- if (enable_track && item == track_item)
- {
- ImGui::TextColored(ImVec4(1,1,0,1), "Item %d", item);
- ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
- }
- else
+ for (int item = 0; item < 100; item++)
{
- ImGui::Text("Item %d", item);
+ if (enable_track && item == track_item)
+ {
+ ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
+ ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
+ }
+ else
+ {
+ ImGui::Text("Item %d", item);
+ }
}
}
float scroll_y = ImGui::GetScrollY();
@@ -2180,23 +2268,26 @@ static void ShowDemoWindowLayout()
{
float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
- ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags);
+ bool window_visible = ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, child_flags);
if (scroll_to_off)
ImGui::SetScrollX(scroll_to_off_px);
if (scroll_to_pos)
ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
- for (int item = 0; item < 100; item++)
+ if (window_visible) // Avoid calling SetScrollHereY when running with culled items
{
- if (enable_track && item == track_item)
- {
- ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
- ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
- }
- else
+ for (int item = 0; item < 100; item++)
{
- ImGui::Text("Item %d", item);
+ if (enable_track && item == track_item)
+ {
+ ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
+ ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
+ }
+ else
+ {
+ ImGui::Text("Item %d", item);
+ }
+ ImGui::SameLine();
}
- ImGui::SameLine();
}
float scroll_x = ImGui::GetScrollX();
float scroll_max_x = ImGui::GetScrollMaxX();
@@ -3027,11 +3118,17 @@ void ImGui::ShowAboutWindow(bool* p_open)
#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
#endif
-#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
- ImGui::Text("define: IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS");
+#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
+ ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
+#endif
+#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
+ ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
+#endif
+#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
+ ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
#endif
-#ifdef IMGUI_DISABLE_MATH_FUNCTIONS
- ImGui::Text("define: IMGUI_DISABLE_MATH_FUNCTIONS");
+#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
+ ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
#endif
#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
@@ -3158,7 +3255,7 @@ void ImGui::ShowFontSelector(const char* label)
HelpMarker(
"- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
"- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
- "- Read FAQ and documentation in misc/fonts/ for more details.\n"
+ "- Read FAQ and docs/FONTS.txt for more details.\n"
"- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
}
@@ -3198,7 +3295,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
if (ImGui::Button("Revert Ref"))
style = *ref;
ImGui::SameLine();
- HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere.");
+ HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export\" below to save them somewhere.");
ImGui::Separator();
@@ -3246,7 +3343,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
{
static int output_dest = 0;
static bool output_only_modified = true;
- if (ImGui::Button("Export Unsaved"))
+ if (ImGui::Button("Export"))
{
if (output_dest == 0)
ImGui::LogToClipboard();
@@ -3286,7 +3383,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
{
// Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons.
- // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient!
+ // Read the FAQ and docs/FONTS.txt about using icon fonts. It's really easy and super convenient!
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i];
ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i];
}
@@ -3304,7 +3401,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
{
ImGuiIO& io = ImGui::GetIO();
ImFontAtlas* atlas = io.Fonts;
- HelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading.");
+ HelpMarker("Read FAQ and docs/FONTS.txt for details on font loading.");
ImGui::PushItemWidth(120);
for (int i = 0; i < atlas->Fonts.Size; i++)
{
@@ -3324,17 +3421,17 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar);
ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar);
const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface);
- ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt);
+ ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt);
for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
if (const ImFontConfig* cfg = &font->ConfigData[config_i])
ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
{
// Display all glyphs of the fonts in separate pages of 256 characters
- for (int base = 0; base < 0x10000; base += 256)
+ for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
{
int count = 0;
- for (int n = 0; n < 256; n++)
+ for (unsigned int n = 0; n < 256; n++)
count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;
if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
{
@@ -3342,7 +3439,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
float cell_spacing = style.ItemSpacing.y;
ImVec2 base_pos = ImGui::GetCursorScreenPos();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
- for (int n = 0; n < 256; n++)
+ for (unsigned int n = 0; n < 256; n++)
{
ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
diff --git a/imgui/imgui_draw.cpp b/imgui/imgui_draw.cpp
index 845cd04e..8089bbef 100644
--- a/imgui/imgui_draw.cpp
+++ b/imgui/imgui_draw.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.73
+// dear imgui, v1.74
// (drawing and font code)
/*
@@ -1725,7 +1725,8 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed
int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height)
{
- IM_ASSERT(id >= 0x10000);
+ // Breaking change on 2019/11/21 (1.74): ImFontAtlas::AddCustomRectRegular() now requires an ID >= 0x110000 (instead of >= 0x10000)
+ IM_ASSERT(id >= 0x110000);
IM_ASSERT(width > 0 && width <= 0xFFFF);
IM_ASSERT(height > 0 && height <= 0xFFFF);
ImFontAtlasCustomRect r;
@@ -1752,7 +1753,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int
return CustomRects.Size - 1; // Return index
}
-void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
+void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const
{
IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates
IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed
@@ -1905,7 +1906,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
- for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
+ for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
{
if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true)
continue;
@@ -2069,7 +2070,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
const float font_off_x = cfg.GlyphOffset.x;
- const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
+ const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
{
@@ -2080,7 +2081,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
float char_off_x = font_off_x;
if (char_advance_x_org != char_advance_x_mod)
- char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
+ char_off_x += cfg.PixelSnapH ? ImFloor((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
// Register glyph
stbtt_aligned_quad q;
@@ -2189,7 +2190,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
for (int i = 0; i < atlas->CustomRects.Size; i++)
{
const ImFontAtlasCustomRect& r = atlas->CustomRects[i];
- if (r.Font == NULL || r.ID > 0x10000)
+ if (r.Font == NULL || r.ID >= 0x110000)
continue;
IM_ASSERT(r.Font->ContainerAtlas == atlas);
@@ -2453,7 +2454,7 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
text += c_len;
if (c_len == 0)
break;
- if (c < 0x10000)
+ if (c <= IM_UNICODE_CODEPOINT_MAX)
AddChar((ImWchar)c);
}
}
@@ -2467,12 +2468,12 @@ void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
{
- int max_codepoint = 0x10000;
- for (int n = 0; n < max_codepoint; n++)
+ const int max_codepoint = IM_UNICODE_CODEPOINT_MAX;
+ for (int n = 0; n <= max_codepoint; n++)
if (GetBit(n))
{
out_ranges->push_back((ImWchar)n);
- while (n < max_codepoint - 1 && GetBit(n + 1))
+ while (n < max_codepoint && GetBit(n + 1))
n++;
out_ranges->push_back((ImWchar)n);
}
@@ -2591,7 +2592,7 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1,
glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX
if (ConfigData->PixelSnapH)
- glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f);
+ glyph.AdvanceX = IM_ROUND(glyph.AdvanceX);
// Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
DirtyLookupTables = true;
@@ -2601,7 +2602,7 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1,
void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
{
IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
- int index_size = IndexLookup.Size;
+ unsigned int index_size = (unsigned int)IndexLookup.Size;
if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists
return;
@@ -2833,8 +2834,8 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
if (const ImFontGlyph* glyph = FindGlyph(c))
{
float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
- pos.x = (float)(int)pos.x + DisplayOffset.x;
- pos.y = (float)(int)pos.y + DisplayOffset.y;
+ pos.x = IM_FLOOR(pos.x + DisplayOffset.x);
+ pos.y = IM_FLOOR(pos.y + DisplayOffset.y);
draw_list->PrimReserve(6, 4);
draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
}
@@ -2846,8 +2847,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
// Align to be pixel perfect
- pos.x = (float)(int)pos.x + DisplayOffset.x;
- pos.y = (float)(int)pos.y + DisplayOffset.y;
+ pos.x = IM_FLOOR(pos.x + DisplayOffset.x);
+ pos.y = IM_FLOOR(pos.y + DisplayOffset.y);
float x = pos.x;
float y = pos.y;
if (y > clip_rect.w)
@@ -3020,9 +3021,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
x += char_width;
}
- // Give back unused vertices
- draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data));
- draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data));
+ // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action.
+ draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink()
+ draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data);
draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
draw_list->_VtxWritePtr = vtx_write;
draw_list->_IdxWritePtr = idx_write;
@@ -3201,9 +3202,9 @@ static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, uns
{
const unsigned long ADLER_MOD = 65521;
unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
- unsigned long blocklen, i;
+ unsigned long blocklen = buflen % 5552;
- blocklen = buflen % 5552;
+ unsigned long i;
while (buflen) {
for (i=0; i + 7 < blocklen; i += 8) {
s1 += buffer[0], s2 += s1;
@@ -3230,10 +3231,9 @@ static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, uns
static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/)
{
- unsigned int olen;
if (stb__in4(0) != 0x57bC0000) return 0;
if (stb__in4(4) != 0) return 0; // error! stream is > 4GB
- olen = stb_decompress_length(i);
+ const unsigned int olen = stb_decompress_length(i);
stb__barrier_in_b = i;
stb__barrier_out_e = output + olen;
stb__barrier_out_b = output;
diff --git a/imgui/imgui_internal.h b/imgui/imgui_internal.h
index 6d393103..73880098 100644
--- a/imgui/imgui_internal.h
+++ b/imgui/imgui_internal.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.73
+// dear imgui, v1.74
// (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@@ -31,7 +31,7 @@ Index of this file:
#error Must include imgui.h before imgui_internal.h
#endif
-#include <stdio.h> // FILE*
+#include <stdio.h> // FILE*, sscanf
#include <stdlib.h> // NULL, malloc, free, qsort, atoi, atof
#include <math.h> // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf
#include <limits.h> // INT_MIN, INT_MAX
@@ -60,10 +60,19 @@ Index of this file:
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
+// Legacy defines
+#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74
+#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
+#endif
+#ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74
+#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
+#endif
+
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
+struct ImBoolVector; // Store 1-bit per value
struct ImRect; // An axis-aligned rectangle (2 points)
struct ImDrawDataBuilder; // Helper to build a ImDrawData instance
struct ImDrawListSharedData; // Data shared between all ImDrawList instances
@@ -86,7 +95,7 @@ struct ImGuiTabBar; // Storage for a tab bar
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
struct ImGuiWindow; // Storage for one window
struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame)
-struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session)
+struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session)
// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical
@@ -131,24 +140,47 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#endif
//-----------------------------------------------------------------------------
-// Generic helpers
+// Macros
//-----------------------------------------------------------------------------
-#define IM_PI 3.14159265358979323846f
+// Debug Logging
+#ifndef IMGUI_DEBUG_LOG
+#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
+#endif
+
+// Static Asserts
+#if (__cplusplus >= 201100)
+#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "")
+#else
+#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
+#endif
+
+// "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much.
+#define IMGUI_DEBUG_PARANOID 0
+#if IMGUI_DEBUG_PARANOID
+#define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR)
+#else
+#define IM_ASSERT_PARANOID(_EXPR)
+#endif
+
+// Error handling
+// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults.
+#ifndef IM_ASSERT_USER_ERROR
+#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && (_MSG)) // Recoverable User Error
+#endif
+
+// Misc Macros
+#define IM_PI 3.14159265358979323846f
#ifdef _WIN32
-#define IM_NEWLINE "\r\n" // Play it nice with Windows users (2018/05 news: Microsoft announced that Notepad will finally display Unix-style carriage returns!)
+#define IM_NEWLINE "\r\n" // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!)
#else
-#define IM_NEWLINE "\n"
+#define IM_NEWLINE "\n"
#endif
-#define IM_TABSIZE (4)
-#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
+#define IM_TABSIZE (4)
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
-
-// Debug Logging
-#ifndef IMGUI_DEBUG_LOG
-#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
-#endif
+#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds
+#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) //
// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall
#ifdef _MSC_VER
@@ -157,36 +189,34 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#define IMGUI_CDECL
#endif
-// Helpers: UTF-8 <> wchar
-IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
-IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count
-IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
-IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
-IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8
-IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
+//-----------------------------------------------------------------------------
+// Generic helpers
+//-----------------------------------------------------------------------------
+// - Helpers: Misc
+// - Helpers: Bit manipulation
+// - Helpers: String, Formatting
+// - Helpers: UTF-8 <> wchar conversions
+// - Helpers: ImVec2/ImVec4 operators
+// - Helpers: Maths
+// - Helpers: Geometry
+// - Helper: ImBoolVector
+// - Helper: ImPool<>
+// - Helper: ImChunkStream<>
+//-----------------------------------------------------------------------------
// Helpers: Misc
+#define ImQsort qsort
IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0);
IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0);
-IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0);
-IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode);
-static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
-static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
-static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
-static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
-#define ImQsort qsort
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68]
#endif
-// Helpers: Geometry
-IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
-IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
-IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
-IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w);
-IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy);
+// Helpers: Bit manipulation
+static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
+static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
-// Helpers: String
+// Helpers: String, Formatting
IMGUI_API int ImStricmp(const char* str1, const char* str2);
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count);
IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count);
@@ -198,12 +228,23 @@ IMGUI_API const char* ImStreolRange(const char* str, const char* str_end);
IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
IMGUI_API void ImStrTrimBlanks(char* str);
+IMGUI_API const char* ImStrSkipBlank(const char* str);
IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3);
IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3);
IMGUI_API const char* ImParseFormatFindStart(const char* format);
IMGUI_API const char* ImParseFormatFindEnd(const char* format);
IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size);
IMGUI_API int ImParseFormatPrecision(const char* format, int default_value);
+static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
+static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
+
+// Helpers: UTF-8 <> wchar conversions
+IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
+IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count
+IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
+IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
+IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8
+IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
// Helpers: ImVec2/ImVec4 operators
// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.)
@@ -224,9 +265,35 @@ static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs)
static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); }
#endif
+// Helpers: File System
+#if defined(__EMSCRIPTEN__) && !defined(IMGUI_DISABLE_FILE_FUNCTIONS)
+#define IMGUI_DISABLE_FILE_FUNCTIONS
+#endif
+#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
+#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
+typedef void* ImFileHandle;
+static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; }
+static inline bool ImFileClose(ImFileHandle) { return false; }
+static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; }
+static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; }
+static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; }
+#endif
+
+#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
+typedef FILE* ImFileHandle;
+IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode);
+IMGUI_API bool ImFileClose(ImFileHandle file);
+IMGUI_API ImU64 ImFileGetSize(ImFileHandle file);
+IMGUI_API ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file);
+IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file);
+#else
+#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions
+#endif
+IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0);
+
// Helpers: Maths
// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy)
-#ifndef IMGUI_DISABLE_MATH_FUNCTIONS
+#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
static inline float ImFabs(float x) { return fabsf(x); }
static inline float ImSqrt(float x) { return sqrtf(x); }
static inline float ImPow(float x, float y) { return powf(x, y); }
@@ -261,17 +328,25 @@ static inline float ImSaturate(float f)
static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; }
static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; }
static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; }
-static inline float ImFloor(float f) { return (float)(int)f; }
-static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)v.y); }
+static inline float ImFloor(float f) { return (float)(int)(f); }
+static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); }
static inline int ImModPositive(int a, int b) { return (a + b) % b; }
static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
-// Helper: ImBoolVector. Store 1-bit per value.
-// Note that Resize() currently clears the whole vector.
-struct ImBoolVector
+// Helpers: Geometry
+IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
+IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
+IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
+IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w);
+inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; }
+IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy);
+
+// Helper: ImBoolVector
+// Store 1-bit per value. Note that Resize() currently clears the whole vector.
+struct IMGUI_API ImBoolVector
{
ImVector<int> Storage;
ImBoolVector() { }
@@ -281,29 +356,52 @@ struct ImBoolVector
void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; }
};
-// Helper: ImPool<>. Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer,
+// Helper: ImPool<>
+// Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer,
// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object.
typedef int ImPoolIdx;
template<typename T>
struct IMGUI_API ImPool
{
- ImVector<T> Data; // Contiguous data
+ ImVector<T> Buf; // Contiguous data
ImGuiStorage Map; // ID->Index
ImPoolIdx FreeIdx; // Next free idx to use
ImPool() { FreeIdx = 0; }
~ImPool() { Clear(); }
- T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Data[idx] : NULL; }
- T* GetByIndex(ImPoolIdx n) { return &Data[n]; }
- ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (ImPoolIdx)(p - Data.Data); }
- T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Data[*p_idx]; *p_idx = FreeIdx; return Add(); }
- bool Contains(const T* p) const { return (p >= Data.Data && p < Data.Data + Data.Size); }
- void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Data[idx].~T(); } Map.Clear(); Data.clear(); FreeIdx = 0; }
- T* Add() { int idx = FreeIdx; if (idx == Data.Size) { Data.resize(Data.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Data[idx]; } IM_PLACEMENT_NEW(&Data[idx]) T(); return &Data[idx]; }
+ T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; }
+ T* GetByIndex(ImPoolIdx n) { return &Buf[n]; }
+ ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); }
+ T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); }
+ bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); }
+ void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = 0; }
+ T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; }
void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); }
- void Remove(ImGuiID key, ImPoolIdx idx) { Data[idx].~T(); *(int*)&Data[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); }
- void Reserve(int capacity) { Data.reserve(capacity); Map.Data.reserve(capacity); }
- int GetSize() const { return Data.Size; }
+ void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); }
+ void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); }
+ int GetSize() const { return Buf.Size; }
+};
+
+// Helper: ImChunkStream<>
+// Build and iterate a contiguous stream of variable-sized structures.
+// This is used by Settings to store persistent data while reducing allocation count.
+// We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for)
+// The tedious/zealous amount of casting is to avoid -Wcast-align warnings.
+template<typename T>
+struct IMGUI_API ImChunkStream
+{
+ ImVector<char> Buf;
+
+ void clear() { Buf.clear(); }
+ bool empty() const { return Buf.Size == 0; }
+ int size() const { return Buf.Size; }
+ T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); }
+ T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); }
+ T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; }
+ int chunk_size(const T* p) { return ((const int*)p)[-1]; }
+ T* end() { return (T*)(void*)(Buf.Data + Buf.Size); }
+ int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; }
+ T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); }
};
//-----------------------------------------------------------------------------
@@ -323,7 +421,7 @@ enum ImGuiButtonFlags_
ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED]
ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions
ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine
- ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable interaction if a key modifier is held
+ ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable mouse interaction if a key modifier is held
ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only)
ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)
ImGuiButtonFlags_NoNavFocus = 1 << 13, // don't override navigation focus when activated
@@ -383,6 +481,7 @@ enum ImGuiSeparatorFlags_
// This is going to be exposed in imgui.h when stabilized enough.
enum ImGuiItemFlags_
{
+ ImGuiItemFlags_None = 0,
ImGuiItemFlags_NoTabStop = 1 << 0, // false
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
@@ -401,8 +500,9 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1,
ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues.
- ImGuiItemStatusFlags_HasDeactivated = 1 << 4, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag.
- ImGuiItemStatusFlags_Deactivated = 1 << 5 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
+ ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state.
+ ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag.
+ ImGuiItemStatusFlags_Deactivated = 1 << 6 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
#ifdef IMGUI_ENABLE_TEST_ENGINE
, // [imgui_tests only]
@@ -568,7 +668,7 @@ struct IMGUI_API ImRect
void TranslateY(float dy) { Min.y += dy; Max.y += dy; }
void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display.
void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped.
- void Floor() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; }
+ void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); }
bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; }
};
@@ -621,7 +721,7 @@ struct IMGUI_API ImGuiMenuColumns
ImGuiMenuColumns();
void Update(int count, float spacing, bool clear);
float DeclColumns(float w0, float w1, float w2);
- float CalcExtraSpace(float avail_w);
+ float CalcExtraSpace(float avail_w) const;
};
// Internal state of the currently focused/edited text input box
@@ -659,15 +759,17 @@ struct IMGUI_API ImGuiInputTextState
};
// Windows data saved in imgui.ini file
+// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily.
+// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure)
struct ImGuiWindowSettings
{
- char* Name;
ImGuiID ID;
ImVec2ih Pos;
ImVec2ih Size;
bool Collapsed;
- ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = false; }
+ ImGuiWindowSettings() { ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = false; }
+ char* GetName() { return (char*)(this + 1); }
};
struct ImGuiSettingsHandler
@@ -857,9 +959,7 @@ struct ImGuiPtrOrIndex
struct ImGuiContext
{
bool Initialized;
- bool FrameScopeActive; // Set by NewFrame(), cleared by EndFrame()
- bool FrameScopePushedImplicitWindow; // Set by NewFrame(), cleared by EndFrame()
- bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
+ bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
ImGuiIO IO;
ImGuiStyle Style;
ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
@@ -870,19 +970,22 @@ struct ImGuiContext
int FrameCount;
int FrameCountEnded;
int FrameCountRendered;
+ bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame()
+ bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed
+ bool WithinEndChild; // Set within EndChild()
// Windows state
ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front
ImVector<ImGuiWindow*> WindowsFocusOrder; // Windows, sorted in focus order, back to front
ImVector<ImGuiWindow*> WindowsSortBuffer;
ImVector<ImGuiWindow*> CurrentWindowStack;
- ImGuiStorage WindowsById;
- int WindowsActiveCount;
- ImGuiWindow* CurrentWindow; // Being drawn into
+ ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow*
+ int WindowsActiveCount; // Number of unique windows submitted by frame
+ ImGuiWindow* CurrentWindow; // Window being drawn into
ImGuiWindow* HoveredWindow; // Will catch mouse inputs
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
- ImGuiWindow* WheelingWindow;
+ ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
ImVec2 WheelingWindowRefMousePos;
float WheelingWindowTimer;
@@ -900,8 +1003,9 @@ struct ImGuiContext
bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.
bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state.
bool ActiveIdHasBeenEditedThisFrame;
- int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it)
- int ActiveIdBlockNavInputFlags;
+ ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those directional navigation requests (e.g. can activate a button and move away from it)
+ ImU32 ActiveIdUsingNavInputMask; // Active widget will want to read those nav inputs.
+ ImU64 ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array.
ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
ImGuiWindow* ActiveIdWindow;
ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard)
@@ -909,7 +1013,6 @@ struct ImGuiContext
bool ActiveIdPreviousFrameIsAlive;
bool ActiveIdPreviousFrameHasBeenEditedBefore;
ImGuiWindow* ActiveIdPreviousFrameWindow;
-
ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation.
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
@@ -997,7 +1100,7 @@ struct ImGuiContext
ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets)
int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source
ImVector<unsigned char> DragDropPayloadBufHeap; // We don't expose the ImVector<> directly
- unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads
+ unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads
// Tab bars
ImGuiTabBar* CurrentTabBar;
@@ -1011,9 +1114,9 @@ struct ImGuiContext
ImFont InputTextPasswordFont;
ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets
- float ColorEditLastHue;
+ float ColorEditLastHue; // Backup of last Hue associated to LastColor[3], so we can restore Hue in lossy RGB<>HSV round trips
float ColorEditLastColor[3];
- ImVec4 ColorPickerRef;
+ ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker.
bool DragCurrentAccumDirty;
float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings
float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
@@ -1030,16 +1133,16 @@ struct ImGuiContext
ImVec2 PlatformImeLastPos;
// Settings
- bool SettingsLoaded;
- float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero
- ImGuiTextBuffer SettingsIniData; // In memory .ini settings
- ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers
- ImVector<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries (parsed from the last loaded .ini file and maintained on saving)
+ bool SettingsLoaded;
+ float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero
+ ImGuiTextBuffer SettingsIniData; // In memory .ini settings
+ ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers
+ ImChunkStream<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries
- // Logging
+ // Capture/Logging
bool LogEnabled;
ImGuiLogType LogType;
- FILE* LogFile; // If != NULL log to stdout/ file
+ ImFileHandle LogFile; // If != NULL log to stdout/ file
ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators.
float LogLinePosY;
bool LogLineFirstItem;
@@ -1063,7 +1166,6 @@ struct ImGuiContext
ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData)
{
Initialized = false;
- FrameScopeActive = FrameScopePushedImplicitWindow = false;
Font = NULL;
FontSize = FontBaseSize = 0.0f;
FontAtlasOwnedByContext = shared_font_atlas ? false : true;
@@ -1071,6 +1173,7 @@ struct ImGuiContext
Time = 0.0f;
FrameCount = 0;
FrameCountEnded = FrameCountRendered = -1;
+ WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false;
WindowsActiveCount = 0;
CurrentWindow = NULL;
@@ -1092,17 +1195,16 @@ struct ImGuiContext
ActiveIdHasBeenPressedBefore = false;
ActiveIdHasBeenEditedBefore = false;
ActiveIdHasBeenEditedThisFrame = false;
- ActiveIdAllowNavDirFlags = 0x00;
- ActiveIdBlockNavInputFlags = 0x00;
+ ActiveIdUsingNavDirMask = 0x00;
+ ActiveIdUsingNavInputMask = 0x00;
+ ActiveIdUsingKeyInputMask = 0x00;
ActiveIdClickOffset = ImVec2(-1,-1);
ActiveIdWindow = NULL;
ActiveIdSource = ImGuiInputSource_None;
-
ActiveIdPreviousFrame = 0;
ActiveIdPreviousFrameIsAlive = false;
ActiveIdPreviousFrameHasBeenEditedBefore = false;
ActiveIdPreviousFrameWindow = NULL;
-
LastActiveId = 0;
LastActiveIdTimer = 0.0f;
@@ -1333,9 +1435,9 @@ struct IMGUI_API ImGuiWindow
ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window.
ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar)
ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect.
- ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentsRegionRect over time (from 1.71+ onward).
+ ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward).
ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back().
- ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on.
+ ImRect ContentRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on.
int LastFrameActive; // Last frame number the window was Active.
float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there)
@@ -1344,7 +1446,7 @@ struct IMGUI_API ImGuiWindow
ImGuiStorage StateStorage;
ImVector<ImGuiColumns> ColumnsStorage;
float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale()
- int SettingsIdx; // Index into SettingsWindow[] (indices are always valid as we only grow the array from the back)
+ int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back)
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
ImDrawList DrawListInst;
@@ -1410,7 +1512,7 @@ enum ImGuiTabBarFlagsPrivate_
// Extend ImGuiTabItemFlags_
enum ImGuiTabItemFlagsPrivate_
{
- ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute WidthContents during layout.
+ ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute ContentWidth during layout.
};
// Storage for one active tab item (sizeof() 26~32 bytes)
@@ -1423,9 +1525,9 @@ struct ImGuiTabItem
int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
float Offset; // Position relative to beginning of tab
float Width; // Width currently displayed
- float WidthContents; // Width of actual contents, stored during BeginTabItem() call
+ float ContentWidth; // Width of actual contents, stored during BeginTabItem() call
- ImGuiTabItem() { ID = Flags = 0; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = WidthContents = 0.0f; }
+ ImGuiTabItem() { ID = 0; Flags = 0; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; }
};
// Storage for a tab bar (sizeof() 92~96 bytes)
@@ -1539,8 +1641,8 @@ namespace ImGui
IMGUI_API void PushOverrideID(ImGuiID id);
// Basic Helpers for widget code
- IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f);
- IMGUI_API void ItemSize(const ImRect& bb, float text_offset_y = 0.0f);
+ IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f);
+ IMGUI_API void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f);
IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL);
IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id);
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
@@ -1578,17 +1680,20 @@ namespace ImGui
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);
IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode);
IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f);
- IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate);
+ IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate);
IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again.
IMGUI_API void SetNavID(ImGuiID id, int nav_layer);
IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel);
// Inputs
+ // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions.
+ inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; }
+ inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; }
+ inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; }
IMGUI_API bool IsMouseDragPastThreshold(int button, float lock_threshold = -1.0f);
- inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { const int key_index = GImGui->IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; }
- inline bool IsNavInputDown(ImGuiNavInput n) { return GImGui->IO.NavInputs[n] > 0.0f; }
- inline bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) { return GetNavInputAmount(n, mode) > 0.0f; }
- inline bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) { return (GetNavInputAmount(n1, mode) + GetNavInputAmount(n2, mode)) > 0.0f; }
+ inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; }
+ inline bool IsNavInputDown(ImGuiNavInput n) { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; }
+ inline bool IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm) { return (GetNavInputAmount(n, rm) > 0.0f); }
// Drag and Drop
IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
@@ -1641,7 +1746,7 @@ namespace ImGui
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- // 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while.
+ // [1.71: 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while]
inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); }
inline void RenderBullet(ImVec2 pos) { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); }
#endif
@@ -1654,13 +1759,14 @@ namespace ImGui
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags);
IMGUI_API void Scrollbar(ImGuiAxis axis);
IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners);
- IMGUI_API ImGuiID GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
+ IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
+ IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders
IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags);
// Widgets low-level behaviors
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
- IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power, ImGuiDragFlags flags);
- IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
+ IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags);
+ IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f);
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging
@@ -1676,13 +1782,13 @@ namespace ImGui
// Data type helpers
IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type);
- IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format);
+ IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format);
IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2);
- IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format);
+ IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format);
// InputText
IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
- IMGUI_API bool TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format);
+ IMGUI_API bool TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format);
inline bool TempInputTextIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputTextId == id); }
// Color
@@ -1698,7 +1804,8 @@ namespace ImGui
IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp);
// Debug Tools
- inline void DebugStartItemPicker() { GImGui->DebugItemPickerActive = true; }
+ inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); }
+ inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; }
} // namespace ImGui
diff --git a/imgui/imgui_widgets.cpp b/imgui/imgui_widgets.cpp
index bcd051e5..ec6f51a9 100644
--- a/imgui/imgui_widgets.cpp
+++ b/imgui/imgui_widgets.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.73
+// dear imgui, v1.74
// (widgets code)
/*
@@ -112,6 +112,7 @@ static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const
//-------------------------------------------------------------------------
// [SECTION] Widgets: Text, etc.
//-------------------------------------------------------------------------
+// - TextEx() [Internal]
// - TextUnformatted()
// - Text()
// - TextV()
@@ -212,7 +213,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
text_size.y = (pos - text_pos).y;
ImRect bb(text_pos, text_pos + text_size);
- ItemSize(text_size);
+ ItemSize(text_size, 0.0f);
ItemAdd(bb, 0);
}
else
@@ -221,7 +222,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
ImRect bb(text_pos, text_pos + text_size);
- ItemSize(text_size);
+ ItemSize(text_size, 0.0f);
if (!ItemAdd(bb, 0))
return;
@@ -358,17 +359,18 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
const char* text_begin = g.TempBuffer;
const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
- const float text_base_offset_y = ImMax(0.0f, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
- const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
- const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding
- ItemSize(bb);
+ const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding
+ ImVec2 pos = window->DC.CursorPos;
+ pos.y += window->DC.CurrLineTextBaseOffset;
+ ItemSize(total_size, 0.0f);
+ const ImRect bb(pos, pos + total_size);
if (!ItemAdd(bb, 0))
return;
// Render
ImU32 text_col = GetColorU32(ImGuiCol_Text);
- RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), text_col);
- RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false);
+ RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, g.FontSize*0.5f), text_col);
+ RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false);
}
//-------------------------------------------------------------------------
@@ -486,7 +488,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
{
hovered = true;
SetHoveredID(id);
- if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy
+ if (CalcTypematicRepeatAmount(g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, g.HoveredIdTimer + 0.0001f, 0.70f, 0.00f))
{
pressed = true;
FocusWindow(window);
@@ -547,7 +549,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if (g.NavActivateDownId == id)
{
bool nav_activated_by_code = (g.NavActivateId == id);
- bool nav_activated_by_inputs = IsNavInputPressed(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed);
+ bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed);
if (nav_activated_by_code || nav_activated_by_inputs)
pressed = true;
if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id)
@@ -557,7 +559,6 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
SetActiveID(id, window);
if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus))
SetFocusID(id, window);
- g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
}
}
@@ -691,7 +692,7 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu
const ImGuiID id = window->GetID(str_id);
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
const float default_size = GetFrameHeight();
- ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f);
+ ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f);
if (!ItemAdd(bb, id))
return false;
@@ -773,7 +774,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
return pressed;
}
-ImGuiID ImGui::GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis)
+ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis)
{
return window->GetIDNoKeepAlive(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY");
}
@@ -808,7 +809,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa
const bool horizontal = (axis == ImGuiAxis_X);
ImRect bb = bb_frame;
- bb.Expand(ImVec2(-ImClamp((float)(int)((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f)));
+ bb.Expand(ImVec2(-ImClamp(IM_FLOOR((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_FLOOR((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f)));
// V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)
const float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
@@ -851,7 +852,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, floa
// Apply scroll
// It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position
const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm));
- *p_scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
+ *p_scroll_v = IM_ROUND(scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
// Update values for rendering
scroll_ratio = ImSaturate(*p_scroll_v / scroll_max);
@@ -880,7 +881,7 @@ void ImGui::Scrollbar(ImGuiAxis axis)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- const ImGuiID id = GetScrollbarID(window, axis);
+ const ImGuiID id = GetWindowScrollbarID(window, axis);
KeepAliveID(id);
// Calculate scrollbar bounding box
@@ -1004,12 +1005,12 @@ bool ImGui::Checkbox(const char* label, bool* v)
if (window->DC.ItemFlags & ImGuiItemFlags_MixedValue)
{
// Undocumented tristate/mixed/indeterminate checkbox (#2644)
- ImVec2 pad(ImMax(1.0f, (float)(int)(square_sz / 3.6f)), ImMax(1.0f, (float)(int)(square_sz / 3.6f)));
+ ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)));
window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
}
else if (*v)
{
- const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f));
+ const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
RenderCheckMark(check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad*2.0f);
}
@@ -1057,8 +1058,8 @@ bool ImGui::RadioButton(const char* label, bool active)
return false;
ImVec2 center = check_bb.GetCenter();
- center.x = (float)(int)center.x + 0.5f;
- center.y = (float)(int)center.y + 0.5f;
+ center.x = IM_ROUND(center.x);
+ center.y = IM_ROUND(center.y);
const float radius = (square_sz - 1.0f) * 0.5f;
bool hovered, held;
@@ -1070,7 +1071,7 @@ bool ImGui::RadioButton(const char* label, bool active)
window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
if (active)
{
- const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f));
+ const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16);
}
@@ -1347,7 +1348,7 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float
// Render
const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
- window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, g.Style.FrameRounding);
+ window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f);
return held;
}
@@ -1505,8 +1506,10 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
SetNextWindowPos(pos);
}
+ // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx()
+ ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove;
+
// Horizontally align ourselves with the framed text
- ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(style.FramePadding.x, style.WindowPadding.y));
bool ret = Begin(name, NULL, window_flags);
PopStyleVar();
@@ -1678,25 +1681,25 @@ const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type)
return &GDataTypeInfo[data_type];
}
-int ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format)
+int ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format)
{
// Signedness doesn't matter when pushing integer arguments
if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32)
- return ImFormatString(buf, buf_size, format, *(const ImU32*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const ImU32*)p_data);
if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
- return ImFormatString(buf, buf_size, format, *(const ImU64*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const ImU64*)p_data);
if (data_type == ImGuiDataType_Float)
- return ImFormatString(buf, buf_size, format, *(const float*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const float*)p_data);
if (data_type == ImGuiDataType_Double)
- return ImFormatString(buf, buf_size, format, *(const double*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const double*)p_data);
if (data_type == ImGuiDataType_S8)
- return ImFormatString(buf, buf_size, format, *(const ImS8*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const ImS8*)p_data);
if (data_type == ImGuiDataType_U8)
- return ImFormatString(buf, buf_size, format, *(const ImU8*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const ImU8*)p_data);
if (data_type == ImGuiDataType_S16)
- return ImFormatString(buf, buf_size, format, *(const ImS16*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const ImS16*)p_data);
if (data_type == ImGuiDataType_U16)
- return ImFormatString(buf, buf_size, format, *(const ImU16*)data_ptr);
+ return ImFormatString(buf, buf_size, format, *(const ImU16*)p_data);
IM_ASSERT(0);
return 0;
}
@@ -1753,7 +1756,7 @@ void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void*
// User can input math operators (e.g. +100) to edit a numerical values.
// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess..
-bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format)
+bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format)
{
while (ImCharIsBlankA(*buf))
buf++;
@@ -1779,7 +1782,7 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
int data_backup[2];
const ImGuiDataTypeInfo* type_info = ImGui::DataTypeGetInfo(data_type);
IM_ASSERT(type_info->Size <= sizeof(data_backup));
- memcpy(data_backup, data_ptr, type_info->Size);
+ memcpy(data_backup, p_data, type_info->Size);
if (format == NULL)
format = type_info->ScanFmt;
@@ -1788,7 +1791,7 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
int arg1i = 0;
if (data_type == ImGuiDataType_S32)
{
- int* v = (int*)data_ptr;
+ int* v = (int*)p_data;
int arg0i = *v;
float arg1f = 0.0f;
if (op && sscanf(initial_value_buf, format, &arg0i) < 1)
@@ -1803,7 +1806,7 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
{
// For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
format = "%f";
- float* v = (float*)data_ptr;
+ float* v = (float*)p_data;
float arg0f = *v, arg1f = 0.0f;
if (op && sscanf(initial_value_buf, format, &arg0f) < 1)
return false;
@@ -1817,7 +1820,7 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
else if (data_type == ImGuiDataType_Double)
{
format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis
- double* v = (double*)data_ptr;
+ double* v = (double*)p_data;
double arg0f = *v, arg1f = 0.0;
if (op && sscanf(initial_value_buf, format, &arg0f) < 1)
return false;
@@ -1832,7 +1835,7 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
{
// All other types assign constant
// We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future.
- sscanf(buf, format, data_ptr);
+ sscanf(buf, format, p_data);
}
else
{
@@ -1840,18 +1843,18 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
int v32;
sscanf(buf, format, &v32);
if (data_type == ImGuiDataType_S8)
- *(ImS8*)data_ptr = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX);
+ *(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX);
else if (data_type == ImGuiDataType_U8)
- *(ImU8*)data_ptr = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX);
+ *(ImU8*)p_data = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX);
else if (data_type == ImGuiDataType_S16)
- *(ImS16*)data_ptr = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX);
+ *(ImS16*)p_data = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX);
else if (data_type == ImGuiDataType_U16)
- *(ImU16*)data_ptr = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX);
+ *(ImU16*)p_data = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX);
else
IM_ASSERT(0);
}
- return memcmp(data_backup, data_ptr, type_info->Size) != 0;
+ return memcmp(data_backup, p_data, type_info->Size) != 0;
}
static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
@@ -2021,7 +2024,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
return true;
}
-bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power, ImGuiDragFlags flags)
+bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, float power, ImGuiDragFlags flags)
{
ImGuiContext& g = *GImGui;
if (g.ActiveId == id)
@@ -2036,30 +2039,32 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_s
switch (data_type)
{
- case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)v; bool r = DragBehaviorT<ImS32, ImS32, float >(ImGuiDataType_S32, &v32, v_speed, v_min ? *(const ImS8*) v_min : IM_S8_MIN, v_max ? *(const ImS8*)v_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)v = (ImS8)v32; return r; }
- case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)v; bool r = DragBehaviorT<ImU32, ImS32, float >(ImGuiDataType_U32, &v32, v_speed, v_min ? *(const ImU8*) v_min : IM_U8_MIN, v_max ? *(const ImU8*)v_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)v = (ImU8)v32; return r; }
- case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)v; bool r = DragBehaviorT<ImS32, ImS32, float >(ImGuiDataType_S32, &v32, v_speed, v_min ? *(const ImS16*)v_min : IM_S16_MIN, v_max ? *(const ImS16*)v_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)v = (ImS16)v32; return r; }
- case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)v; bool r = DragBehaviorT<ImU32, ImS32, float >(ImGuiDataType_U32, &v32, v_speed, v_min ? *(const ImU16*)v_min : IM_U16_MIN, v_max ? *(const ImU16*)v_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)v = (ImU16)v32; return r; }
- case ImGuiDataType_S32: return DragBehaviorT<ImS32, ImS32, float >(data_type, (ImS32*)v, v_speed, v_min ? *(const ImS32* )v_min : IM_S32_MIN, v_max ? *(const ImS32* )v_max : IM_S32_MAX, format, power, flags);
- case ImGuiDataType_U32: return DragBehaviorT<ImU32, ImS32, float >(data_type, (ImU32*)v, v_speed, v_min ? *(const ImU32* )v_min : IM_U32_MIN, v_max ? *(const ImU32* )v_max : IM_U32_MAX, format, power, flags);
- case ImGuiDataType_S64: return DragBehaviorT<ImS64, ImS64, double>(data_type, (ImS64*)v, v_speed, v_min ? *(const ImS64* )v_min : IM_S64_MIN, v_max ? *(const ImS64* )v_max : IM_S64_MAX, format, power, flags);
- case ImGuiDataType_U64: return DragBehaviorT<ImU64, ImS64, double>(data_type, (ImU64*)v, v_speed, v_min ? *(const ImU64* )v_min : IM_U64_MIN, v_max ? *(const ImU64* )v_max : IM_U64_MAX, format, power, flags);
- case ImGuiDataType_Float: return DragBehaviorT<float, float, float >(data_type, (float*)v, v_speed, v_min ? *(const float* )v_min : -FLT_MAX, v_max ? *(const float* )v_max : FLT_MAX, format, power, flags);
- case ImGuiDataType_Double: return DragBehaviorT<double,double,double>(data_type, (double*)v, v_speed, v_min ? *(const double*)v_min : -DBL_MAX, v_max ? *(const double*)v_max : DBL_MAX, format, power, flags);
+ case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT<ImS32, ImS32, float>(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, power, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }
+ case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT<ImU32, ImS32, float>(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, power, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; }
+ case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT<ImS32, ImS32, float>(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, power, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }
+ case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT<ImU32, ImS32, float>(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, power, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }
+ case ImGuiDataType_S32: return DragBehaviorT<ImS32, ImS32, float >(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, power, flags);
+ case ImGuiDataType_U32: return DragBehaviorT<ImU32, ImS32, float >(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, power, flags);
+ case ImGuiDataType_S64: return DragBehaviorT<ImS64, ImS64, double>(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, power, flags);
+ case ImGuiDataType_U64: return DragBehaviorT<ImU64, ImS64, double>(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, power, flags);
+ case ImGuiDataType_Float: return DragBehaviorT<float, float, float >(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, power, flags);
+ case ImGuiDataType_Double: return DragBehaviorT<double,double,double>(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, power, flags);
case ImGuiDataType_COUNT: break;
}
IM_ASSERT(0);
return false;
}
-bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power)
+// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional.
+// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
+bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
if (power != 1.0f)
- IM_ASSERT(v_min != NULL && v_max != NULL); // When using a power curve the drag needs to have known bounds
+ IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
@@ -2093,7 +2098,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
- g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
+ g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id)
{
temp_input_start = true;
@@ -2102,7 +2107,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
}
}
if (temp_input_is_active || temp_input_start)
- return TempInputTextScalar(frame_bb, id, label, data_type, v, format);
+ return TempInputTextScalar(frame_bb, id, label, data_type, p_data, format);
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
@@ -2110,13 +2115,13 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
// Drag behavior
- const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None);
+ const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, power, ImGuiDragFlags_None);
if (value_changed)
MarkItemEdited(id);
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
char value_buf[64];
- const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format);
+ const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
if (label_size.x > 0.0f)
@@ -2126,7 +2131,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
return value_changed;
}
-bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power)
+bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2143,10 +2148,10 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int
PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
- value_changed |= DragScalar("", data_type, v, v_speed, v_min, v_max, format, power);
+ value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, power);
PopID();
PopItemWidth();
- v = (void*)((char*)v + type_size);
+ p_data = (void*)((char*)p_data + type_size);
}
PopID();
@@ -2430,7 +2435,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
FLOATTYPE v_new_off_f = (v_max - v_min) * clicked_t;
TYPE v_new_off_floor = (TYPE)(v_new_off_f);
TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5);
- if (!is_decimal && v_new_off_floor < v_new_off_round)
+ if (v_new_off_floor < v_new_off_round)
v_new = v_min + v_new_off_round;
else
v_new = v_min + v_new_off_floor;
@@ -2469,42 +2474,44 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
return value_changed;
}
-// For 32-bits and larger types, slider bounds are limited to half the natural type range.
+// For 32-bit and larger types, slider bounds are limited to half the natural type range.
// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok.
// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders.
-bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb)
+bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb)
{
switch (data_type)
{
- case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)v; bool r = SliderBehaviorT<ImS32, ImS32, float >(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)v_min, *(const ImS8*)v_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)v = (ImS8)v32; return r; }
- case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)v; bool r = SliderBehaviorT<ImU32, ImS32, float >(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)v_min, *(const ImU8*)v_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)v = (ImU8)v32; return r; }
- case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)v; bool r = SliderBehaviorT<ImS32, ImS32, float >(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)v_min, *(const ImS16*)v_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)v = (ImS16)v32; return r; }
- case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)v; bool r = SliderBehaviorT<ImU32, ImS32, float >(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)v_min, *(const ImU16*)v_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)v = (ImU16)v32; return r; }
+ case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT<ImS32, ImS32, float>(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }
+ case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT<ImU32, ImS32, float>(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; }
+ case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT<ImS32, ImS32, float>(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; }
+ case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT<ImU32, ImS32, float>(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, power, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; }
case ImGuiDataType_S32:
- IM_ASSERT(*(const ImS32*)v_min >= IM_S32_MIN/2 && *(const ImS32*)v_max <= IM_S32_MAX/2);
- return SliderBehaviorT<ImS32, ImS32, float >(bb, id, data_type, (ImS32*)v, *(const ImS32*)v_min, *(const ImS32*)v_max, format, power, flags, out_grab_bb);
+ IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN/2 && *(const ImS32*)p_max <= IM_S32_MAX/2);
+ return SliderBehaviorT<ImS32, ImS32, float >(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, power, flags, out_grab_bb);
case ImGuiDataType_U32:
- IM_ASSERT(*(const ImU32*)v_max <= IM_U32_MAX/2);
- return SliderBehaviorT<ImU32, ImS32, float >(bb, id, data_type, (ImU32*)v, *(const ImU32*)v_min, *(const ImU32*)v_max, format, power, flags, out_grab_bb);
+ IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX/2);
+ return SliderBehaviorT<ImU32, ImS32, float >(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, power, flags, out_grab_bb);
case ImGuiDataType_S64:
- IM_ASSERT(*(const ImS64*)v_min >= IM_S64_MIN/2 && *(const ImS64*)v_max <= IM_S64_MAX/2);
- return SliderBehaviorT<ImS64, ImS64, double>(bb, id, data_type, (ImS64*)v, *(const ImS64*)v_min, *(const ImS64*)v_max, format, power, flags, out_grab_bb);
+ IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN/2 && *(const ImS64*)p_max <= IM_S64_MAX/2);
+ return SliderBehaviorT<ImS64, ImS64, double>(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, power, flags, out_grab_bb);
case ImGuiDataType_U64:
- IM_ASSERT(*(const ImU64*)v_max <= IM_U64_MAX/2);
- return SliderBehaviorT<ImU64, ImS64, double>(bb, id, data_type, (ImU64*)v, *(const ImU64*)v_min, *(const ImU64*)v_max, format, power, flags, out_grab_bb);
+ IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX/2);
+ return SliderBehaviorT<ImU64, ImS64, double>(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, power, flags, out_grab_bb);
case ImGuiDataType_Float:
- IM_ASSERT(*(const float*)v_min >= -FLT_MAX/2.0f && *(const float*)v_max <= FLT_MAX/2.0f);
- return SliderBehaviorT<float, float, float >(bb, id, data_type, (float*)v, *(const float*)v_min, *(const float*)v_max, format, power, flags, out_grab_bb);
+ IM_ASSERT(*(const float*)p_min >= -FLT_MAX/2.0f && *(const float*)p_max <= FLT_MAX/2.0f);
+ return SliderBehaviorT<float, float, float >(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, power, flags, out_grab_bb);
case ImGuiDataType_Double:
- IM_ASSERT(*(const double*)v_min >= -DBL_MAX/2.0f && *(const double*)v_max <= DBL_MAX/2.0f);
- return SliderBehaviorT<double,double,double>(bb, id, data_type, (double*)v, *(const double*)v_min, *(const double*)v_max, format, power, flags, out_grab_bb);
+ IM_ASSERT(*(const double*)p_min >= -DBL_MAX/2.0f && *(const double*)p_max <= DBL_MAX/2.0f);
+ return SliderBehaviorT<double,double,double>(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, power, flags, out_grab_bb);
case ImGuiDataType_COUNT: break;
}
IM_ASSERT(0);
return false;
}
-bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power)
+// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required.
+// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
+bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2542,7 +2549,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
- g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
+ g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
if (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id)
{
temp_input_start = true;
@@ -2551,7 +2558,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
}
}
if (temp_input_is_active || temp_input_start)
- return TempInputTextScalar(frame_bb, id, label, data_type, v, format);
+ return TempInputTextScalar(frame_bb, id, label, data_type, p_data, format);
// Draw frame
const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
@@ -2560,7 +2567,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
// Slider behavior
ImRect grab_bb;
- const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_None, &grab_bb);
+ const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_None, &grab_bb);
if (value_changed)
MarkItemEdited(id);
@@ -2570,7 +2577,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
char value_buf[64];
- const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format);
+ const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f));
if (label_size.x > 0.0f)
@@ -2666,7 +2673,7 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const
return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format);
}
-bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power)
+bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2696,7 +2703,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
- g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
+ g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
}
// Draw frame
@@ -2706,7 +2713,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
// Slider behavior
ImRect grab_bb;
- const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical, &grab_bb);
+ const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, power, ImGuiSliderFlags_Vertical, &grab_bb);
if (value_changed)
MarkItemEdited(id);
@@ -2717,7 +2724,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
// For the vertical slider we allow centered text to overlap the frame padding
char value_buf[64];
- const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format);
+ const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
@@ -2830,7 +2837,7 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets)
// FIXME: Facilitate using this in variety of other situations.
-bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
+bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format)
{
ImGuiContext& g = *GImGui;
@@ -2843,7 +2850,7 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label,
char fmt_buf[32];
char data_buf[32];
format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf));
- DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format);
+ DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format);
ImStrTrimBlanks(data_buf);
g.CurrentWindow->DC.CursorPos = bb.Min;
@@ -2858,14 +2865,16 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label,
}
if (value_changed)
{
- value_changed = DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL);
+ value_changed = DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL);
if (value_changed)
MarkItemEdited(id);
}
return value_changed;
}
-bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags)
+// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step and p_step_fast are optional.
+// Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
+bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2878,7 +2887,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
format = DataTypeGetInfo(data_type)->PrintFmt;
char buf[64];
- DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format);
+ DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
bool value_changed = false;
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
@@ -2886,7 +2895,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
flags |= ImGuiInputTextFlags_AutoSelectAll;
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselve by comparing the actual data rather than the string.
- if (step != NULL)
+ if (p_step != NULL)
{
const float button_size = GetFrameHeight();
@@ -2894,7 +2903,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
PushID(label);
SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
- value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
+ value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format);
// Step buttons
const ImVec2 backup_frame_padding = style.FramePadding;
@@ -2905,13 +2914,13 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
SameLine(0, style.ItemInnerSpacing.x);
if (ButtonEx("-", ImVec2(button_size, button_size), button_flags))
{
- DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
+ DataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
value_changed = true;
}
SameLine(0, style.ItemInnerSpacing.x);
if (ButtonEx("+", ImVec2(button_size, button_size), button_flags))
{
- DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
+ DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
value_changed = true;
}
@@ -2929,7 +2938,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
else
{
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
- value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
+ value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format);
}
if (value_changed)
MarkItemEdited(window->DC.LastItemId);
@@ -2937,7 +2946,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
return value_changed;
}
-bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags)
+bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2954,10 +2963,10 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in
PushID(i);
if (i > 0)
SameLine(0, g.Style.ItemInnerSpacing.x);
- value_changed |= InputScalar("", data_type, v, step, step_fast, format, flags);
+ value_changed |= InputScalar("", data_type, p_data, p_step, p_step_fast, format, flags);
PopID();
PopItemWidth();
- v = (void*)((char*)v + type_size);
+ p_data = (void*)((char*)p_data + type_size);
}
PopID();
@@ -3148,7 +3157,7 @@ namespace ImStb
static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->TextW[idx]; }
static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); }
-static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
+static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; }
static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
{
@@ -3323,10 +3332,18 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
return false;
}
+ // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817)
+ if (c == 127)
+ return false;
+
// Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME)
if (c >= 0xE000 && c <= 0xF8FF)
return false;
+ // Filter Unicode ranges we are not handling in this build.
+ if (c > IM_UNICODE_CODEPOINT_MAX)
+ return false;
+
// Generic named filters
if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific))
{
@@ -3404,11 +3421,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
BeginGroup();
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
- ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
- const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
- const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
+ const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
+ const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y);
+
+ const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
+ const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size);
ImGuiWindow* draw_window = window;
+ ImVec2 inner_size = frame_size;
if (is_multiline)
{
if (!ItemAdd(total_bb, id, &frame_bb))
@@ -3423,9 +3443,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
EndGroup();
return false;
}
- draw_window = GetCurrentWindow();
+ draw_window = g.CurrentWindow; // Child window
draw_window->DC.NavLayerActiveMaskNext |= draw_window->DC.NavLayerCurrentMask; // This is to ensure that EndChild() will display a navigation highlight
- size.x -= draw_window->ScrollbarSizes.x;
+ inner_size.x -= draw_window->ScrollbarSizes.x;
}
else
{
@@ -3448,8 +3468,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const bool user_clicked = hovered && io.MouseClicked[0];
const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard));
- const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetScrollbarID(draw_window, ImGuiAxis_Y);
- const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y);
+ const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
+ const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
bool clear_active_id = false;
bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline);
@@ -3505,12 +3525,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
SetActiveID(id, window);
SetFocusID(id, window);
FocusWindow(window);
+
+ // Declare our inputs
IM_ASSERT(ImGuiNavInput_COUNT < 32);
- g.ActiveIdBlockNavInputFlags = (1 << ImGuiNavInput_Cancel);
+ g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
+ if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory))
+ g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
+ g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);
+ g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 << ImGuiKey_End);
+ if (is_multiline)
+ g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU64)1 << ImGuiKey_PageDown); // FIXME-NAV: Page up/down actually not supported yet by widget, but claim them ahead.
if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character.
- g.ActiveIdBlockNavInputFlags |= (1 << ImGuiNavInput_KeyTab_);
- if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
- g.ActiveIdAllowNavDirFlags = ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
+ g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab);
}
// We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function)
@@ -3741,7 +3767,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
s += ImTextCharFromUtf8(&c, s, NULL);
if (c == 0)
break;
- if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, callback_user_data))
+ if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data))
continue;
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
}
@@ -3909,7 +3935,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
}
- const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
+ const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y); // Not using frame_bb.Max because we have adjusted size
ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
ImVec2 text_size(0.0f, 0.0f);
@@ -3965,7 +3991,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
searches_remaining += is_multiline ? 1 : 0;
int line_count = 0;
- //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bits
+ //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit
for (const ImWchar* s = text_begin; *s != 0; s++)
if (*s == '\n')
{
@@ -3990,7 +4016,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
if (is_multiline)
- text_size = ImVec2(size.x, line_count * g.FontSize);
+ text_size = ImVec2(inner_size.x, line_count * g.FontSize);
}
// Scroll
@@ -3999,11 +4025,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// Horizontal scroll in chunks of quarter width
if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
{
- const float scroll_increment_x = size.x * 0.25f;
+ const float scroll_increment_x = inner_size.x * 0.25f;
if (cursor_offset.x < state->ScrollX)
- state->ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
- else if (cursor_offset.x - size.x >= state->ScrollX)
- state->ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
+ state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x));
+ else if (cursor_offset.x - inner_size.x >= state->ScrollX)
+ state->ScrollX = IM_FLOOR(cursor_offset.x - inner_size.x + scroll_increment_x);
}
else
{
@@ -4016,8 +4042,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
float scroll_y = draw_window->Scroll.y;
if (cursor_offset.y - g.FontSize < scroll_y)
scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
- else if (cursor_offset.y - size.y >= scroll_y)
- scroll_y = cursor_offset.y - size.y;
+ else if (cursor_offset.y - inner_size.y >= scroll_y)
+ scroll_y = cursor_offset.y - inner_size.y;
draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
draw_window->Scroll.y = scroll_y;
}
@@ -4042,7 +4068,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
break;
if (rect_pos.y < clip_rect.y)
{
- //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bits
+ //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit
//p = p ? p + 1 : text_selected_end;
while (p < text_selected_end)
if (*p++ == '\n')
@@ -4051,7 +4077,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
else
{
ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
- if (rect_size.x <= 0.0f) rect_size.x = (float)(int)(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
+ if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn));
rect.ClipWith(clip_rect);
if (rect.Overlaps(clip_rect))
@@ -4088,7 +4114,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{
// Render text only (no selection, no cursor)
if (is_multiline)
- text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width
+ text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width
else if (!is_displaying_hint && g.ActiveId == id)
buf_display_end = buf_display + state->CurLenA;
else if (!is_displaying_hint)
@@ -4218,8 +4244,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
{
// RGB/HSV 0..255 Sliders
- const float w_item_one = ImMax(1.0f, (float)(int)((w_inputs - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
- const float w_item_last = ImMax(1.0f, (float)(int)(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
+ const float w_item_one = ImMax(1.0f, IM_FLOOR((w_inputs - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
+ const float w_item_last = ImMax(1.0f, IM_FLOOR(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
static const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
@@ -4494,7 +4520,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
- float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f);
+ float bars_triangles_half_sz = IM_FLOOR(bars_width * 0.20f);
float backup_initial_col[4];
memcpy(backup_initial_col, col, components * sizeof(float));
@@ -4763,7 +4789,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
draw_list->PrimVtx(trb, uv_white, hue_color32);
draw_list->PrimVtx(trc, uv_white, col_white);
draw_list->PrimVtx(tra, uv_white, 0);
- draw_list->PrimVtx(trb, uv_white, col_white);
+ draw_list->PrimVtx(trb, uv_white, col_black);
draw_list->PrimVtx(trc, uv_white, 0);
draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f);
sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
@@ -4774,13 +4800,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white);
draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black);
RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f);
- sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much
- sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
+ sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much
+ sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
// Render Hue Bar
for (int i = 0; i < 6; ++i)
draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]);
- float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f);
+ float bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size);
RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
}
@@ -4798,7 +4824,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK);
- float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f);
+ float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size);
RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
}
@@ -4855,7 +4881,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
bb_inner.Expand(off);
if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f)
{
- float mid_x = (float)(int)((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f);
+ float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f);
RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight| ImDrawCornerFlags_BotRight);
window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawCornerFlags_TopLeft|ImDrawCornerFlags_BotLeft);
}
@@ -5190,7 +5216,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
- const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f);
+ const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y));
if (!label_end)
label_end = FindRenderedTextEnd(label);
@@ -5207,21 +5233,21 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
{
// Framed header expand a little outside the default padding, to the edge of InnerClipRect
// (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f)
- frame_bb.Min.x -= (float)(int)(window->WindowPadding.x * 0.5f - 1.0f);
- frame_bb.Max.x += (float)(int)(window->WindowPadding.x * 0.5f);
+ frame_bb.Min.x -= IM_FLOOR(window->WindowPadding.x * 0.5f - 1.0f);
+ frame_bb.Max.x += IM_FLOOR(window->WindowPadding.x * 0.5f);
}
const float text_offset_x = g.FontSize + (display_frame ? padding.x*3 : padding.x*2); // Collapser arrow width + Spacing
const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser
ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y);
- ItemSize(ImVec2(text_width, frame_height), text_offset_y);
+ ItemSize(ImVec2(text_width, frame_height), padding.y);
// For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
ImRect interact_bb = frame_bb;
if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0)
interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f;
-
+
// Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child.
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
// This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
@@ -5247,7 +5273,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// - OpenOnDoubleClick .............. double-click anywhere to open
// - OpenOnArrow .................... single-click on arrow to open
// - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
- ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers;
+ ImGuiButtonFlags button_flags = 0;
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
button_flags |= ImGuiButtonFlags_AllowItemOverlap;
if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
@@ -5255,21 +5281,31 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (!is_leaf)
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
+ // We allow clicking on the arrow section with keyboard modifiers held, in order to easily
+ // allow browsing a tree while preserving selection with code implementing multi-selection patterns.
+ // When clicking on the rest of the tree node we always disallow keyboard modifiers.
+ const float hit_padding_x = style.TouchExtraPadding.x;
+ const float arrow_hit_x1 = (text_pos.x - text_offset_x) - hit_padding_x;
+ const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + hit_padding_x;
+ if (window != g.HoveredWindow || !(g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2))
+ button_flags |= ImGuiButtonFlags_NoKeyModifiers;
+
bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0;
const bool was_selected = selected;
bool hovered, held;
bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
- bool toggled = false;
if (!is_leaf)
{
+ bool toggled = false;
if (pressed)
{
- toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id);
+ if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id))
+ toggled = true;
if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
- toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)) && (!g.NavDisableMouseHover);
- if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
- toggled |= g.IO.MouseDoubleClicked[0];
+ toggled |= (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2) && (!g.NavDisableMouseHover); // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job
+ if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0])
+ toggled = true;
if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
toggled = false;
}
@@ -5289,6 +5325,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
{
is_open = !is_open;
window->DC.StateStorage->SetInt(id, is_open);
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
}
}
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
@@ -5484,7 +5521,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
ImVec2 pos = window->DC.CursorPos;
pos.y += window->DC.CurrLineTextBaseOffset;
ImRect bb_inner(pos, pos + size);
- ItemSize(size);
+ ItemSize(size, 0.0f);
// Fill horizontal space.
ImVec2 window_padding = window->WindowPadding;
@@ -5498,8 +5535,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// Selectables are tightly packed together so we extend the box to cover spacing between selectable.
const float spacing_x = style.ItemSpacing.x;
const float spacing_y = style.ItemSpacing.y;
- const float spacing_L = (float)(int)(spacing_x * 0.50f);
- const float spacing_U = (float)(int)(spacing_y * 0.50f);
+ const float spacing_L = IM_FLOOR(spacing_x * 0.50f);
+ const float spacing_U = IM_FLOOR(spacing_y * 0.50f);
bb.Min.x -= spacing_L;
bb.Min.y -= spacing_U;
bb.Max.x += (spacing_x - spacing_L);
@@ -5920,10 +5957,10 @@ void ImGui::Value(const char* prefix, float v, const char* float_format)
// [SECTION] MenuItem, BeginMenu, EndMenu, etc.
//-------------------------------------------------------------------------
// - ImGuiMenuColumns [Internal]
-// - BeginMainMenuBar()
-// - EndMainMenuBar()
// - BeginMenuBar()
// - EndMenuBar()
+// - BeginMainMenuBar()
+// - EndMainMenuBar()
// - BeginMenu()
// - EndMenu()
// - MenuItem()
@@ -5949,7 +5986,7 @@ void ImGuiMenuColumns::Update(int count, float spacing, bool clear)
{
if (i > 0 && NextWidths[i] > 0.0f)
Width += Spacing;
- Pos[i] = (float)(int)Width;
+ Pos[i] = IM_FLOOR(Width);
Width += NextWidths[i];
NextWidths[i] = 0.0f;
}
@@ -5966,45 +6003,11 @@ float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using v
return ImMax(Width, NextWidth);
}
-float ImGuiMenuColumns::CalcExtraSpace(float avail_w)
+float ImGuiMenuColumns::CalcExtraSpace(float avail_w) const
{
return ImMax(0.0f, avail_w - Width);
}
-// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
-bool ImGui::BeginMainMenuBar()
-{
- ImGuiContext& g = *GImGui;
- g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f));
- SetNextWindowPos(ImVec2(0.0f, 0.0f));
- SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y));
- PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
- PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0));
- ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
- bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
- PopStyleVar(2);
- g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
- if (!is_open)
- {
- End();
- return false;
- }
- return true; //-V1020
-}
-
-void ImGui::EndMainMenuBar()
-{
- EndMenuBar();
-
- // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
- // FIXME: With this strategy we won't be able to restore a NULL focus.
- ImGuiContext& g = *GImGui;
- if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0 && !g.NavAnyRequest)
- FocusTopMostWindowUnderOne(g.NavWindow, NULL);
-
- End();
-}
-
// FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere..
// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer.
// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary.
@@ -6024,7 +6027,7 @@ bool ImGui::BeginMenuBar()
// We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
// We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.
ImRect bar_rect = window->MenuBarRect();
- ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f));
+ ImRect clip_rect(IM_ROUND(bar_rect.Min.x), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding)), IM_ROUND(bar_rect.Max.y));
clip_rect.ClipWith(window->OuterRectClipped);
PushClipRect(clip_rect.Min, clip_rect.Max, false);
@@ -6078,6 +6081,40 @@ void ImGui::EndMenuBar()
window->DC.MenuBarAppending = false;
}
+// For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
+bool ImGui::BeginMainMenuBar()
+{
+ ImGuiContext& g = *GImGui;
+ g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f));
+ SetNextWindowPos(ImVec2(0.0f, 0.0f));
+ SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y));
+ PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
+ PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0));
+ ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
+ bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
+ PopStyleVar(2);
+ g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
+ if (!is_open)
+ {
+ End();
+ return false;
+ }
+ return true; //-V1020
+}
+
+void ImGui::EndMainMenuBar()
+{
+ EndMenuBar();
+
+ // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
+ // FIXME: With this strategy we won't be able to restore a NULL focus.
+ ImGuiContext& g = *GImGui;
+ if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0 && !g.NavAnyRequest)
+ FocusTopMostWindowUnderOne(g.NavWindow, NULL);
+
+ End();
+}
+
bool ImGui::BeginMenu(const char* label, bool enabled)
{
ImGuiWindow* window = GetCurrentWindow();
@@ -6106,19 +6143,19 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
// Menu inside an horizontal menu bar
// Selectable extend their highlight by half ItemSpacing in each direction.
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
- popup_pos = ImVec2(pos.x - 1.0f - (float)(int)(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight());
- window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
+ popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight());
+ window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f);
PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
float w = label_size.x;
pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
PopStyleVar();
- window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
+ window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
}
else
{
// Menu inside a menu
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
- float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
+ float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, IM_FLOOR(g.FontSize * 1.20f)); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
ImU32 text_col = GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled);
@@ -6257,16 +6294,16 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo
// Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful
// Note that in this situation we render neither the shortcut neither the selected tick mark
float w = label_size.x;
- window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
+ window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f);
PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
pressed = Selectable(label, false, flags, ImVec2(w, 0.0f));
PopStyleVar();
- window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
+ window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
}
else
{
ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f);
- float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame
+ float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, IM_FLOOR(g.FontSize * 1.20f)); // Feedback for next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
pressed = Selectable(label, false, flags | ImGuiSelectableFlags_DrawFillAvailWidth, ImVec2(w, 0.0f));
if (shortcut_size.x > 0.0f)
@@ -6415,15 +6452,15 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
tab_bar->FramePadding = g.Style.FramePadding;
// Layout
- ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, tab_bar->BarRect.GetHeight()));
+ ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y);
window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
// Draw separator
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive);
const float y = tab_bar->BarRect.Max.y - 1.0f;
{
- const float separator_min_x = tab_bar->BarRect.Min.x - ImFloor(window->WindowPadding.x * 0.5f);
- const float separator_max_x = tab_bar->BarRect.Max.x + ImFloor(window->WindowPadding.x * 0.5f);
+ const float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f);
+ const float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f);
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
}
return true;
@@ -6439,8 +6476,8 @@ void ImGui::EndTabBar()
ImGuiTabBar* tab_bar = g.CurrentTabBar;
if (tab_bar == NULL)
{
- IM_ASSERT(tab_bar != NULL && "Mismatched BeginTabBar()/EndTabBar()!");
- return; // FIXME-ERRORHANDLING
+ IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!");
+ return;
}
if (tab_bar->WantLayout)
TabBarLayout(tab_bar);
@@ -6542,13 +6579,13 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
const char* tab_name = tab_bar->GetTabName(tab);
const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true;
- tab->WidthContents = TabItemCalcSize(tab_name, has_close_button).x;
+ tab->ContentWidth = TabItemCalcSize(tab_name, has_close_button).x;
- width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents;
+ width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->ContentWidth;
// Store data so we can build an array sorted by width if we need to shrink tabs down
g.ShrinkWidthBuffer[tab_n].Index = tab_n;
- g.ShrinkWidthBuffer[tab_n].Width = tab->WidthContents;
+ g.ShrinkWidthBuffer[tab_n].Width = tab->ContentWidth;
}
// Compute width
@@ -6560,7 +6597,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// If we don't have enough room, resize down the largest tabs first
ShrinkWidths(g.ShrinkWidthBuffer.Data, g.ShrinkWidthBuffer.Size, width_excess);
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
- tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = (float)(int)g.ShrinkWidthBuffer[tab_n].Width;
+ tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width);
}
else
{
@@ -6568,7 +6605,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
- tab->Width = ImMin(tab->WidthContents, tab_max_width);
+ tab->Width = ImMin(tab->ContentWidth, tab_max_width);
IM_ASSERT(tab->Width > 0.0f);
}
}
@@ -6584,7 +6621,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID)
scroll_track_selected_tab_id = tab->ID;
offset_x += tab->Width + g.Style.ItemInnerSpacing.x;
- offset_x_ideal += tab->WidthContents + g.Style.ItemInnerSpacing.x;
+ offset_x_ideal += tab->ContentWidth + g.Style.ItemInnerSpacing.x;
}
tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f);
tab_bar->OffsetMaxIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f);
@@ -6836,8 +6873,8 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f
ImGuiTabBar* tab_bar = g.CurrentTabBar;
if (tab_bar == NULL)
{
- IM_ASSERT(tab_bar && "Needs to be called between BeginTabBar() and EndTabBar()!");
- return false; // FIXME-ERRORHANDLING
+ IM_ASSERT_USER_ERROR(tab_bar, "BeginTabItem() Needs to be called between BeginTabBar() and EndTabBar()!");
+ return false;
}
bool ret = TabItemEx(tab_bar, label, p_open, flags);
if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
@@ -6905,7 +6942,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
tab_is_new = true;
}
tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab);
- tab->WidthContents = size.x;
+ tab->ContentWidth = size.x;
if (p_open == NULL)
flags |= ImGuiTabItemFlags_NoCloseButton;
@@ -6961,7 +6998,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Layout
size.x = tab->Width;
- window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2((float)(int)tab->Offset - tab_bar->ScrollingAnim, 0.0f);
+ window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f);
ImVec2 pos = window->DC.CursorPos;
ImRect bb(pos, pos + size);
@@ -7016,10 +7053,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
}
#if 0
- if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->WidthContents)
+ if (hovered && g.HoveredIdNotActiveTimer > 0.50f && bb.GetWidth() < tab->ContentWidth)
{
// Enlarge tab display when hovering
- bb.Max.x = bb.Min.x + (float)(int)ImLerp(bb.GetWidth(), tab->WidthContents, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f));
+ bb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f)));
display_draw_list = GetForegroundDrawList(window);
TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive));
}
@@ -7129,7 +7166,7 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
if (flags & ImGuiTabItemFlags_UnsavedDocument)
{
text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x;
- ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + (float)(int)(-g.FontSize * 0.25f));
+ ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + IM_FLOOR(-g.FontSize * 0.25f));
RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL);
}
ImRect text_ellipsis_clip_bb = text_pixel_clip_bb;
@@ -7419,8 +7456,8 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
{
// Compute clipping rectangle
ImGuiColumnData* column = &columns->Columns[n];
- float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n));
- float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
+ float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n));
+ float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
column->ClipRect.ClipWith(window->ClipRect);
}
@@ -7438,7 +7475,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
float width = offset_1 - offset_0;
PushItemWidth(width * 0.65f);
window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);
- window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+ window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;
}
@@ -7453,7 +7490,7 @@ void ImGui::NextColumn()
if (columns->Count == 1)
{
- window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+ window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
IM_ASSERT(columns->Current == 0);
return;
}
@@ -7478,7 +7515,7 @@ void ImGui::NextColumn()
columns->Current = 0;
columns->LineMinY = columns->LineMaxY;
}
- window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+ window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = columns->LineMinY;
window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
window->DC.CurrLineTextBaseOffset = 0.0f;
@@ -7545,7 +7582,7 @@ void ImGui::EndColumns()
// Draw column
const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
- const float xi = (float)(int)x;
+ const float xi = IM_FLOOR(x);
window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
}
@@ -7565,7 +7602,7 @@ void ImGui::EndColumns()
window->WorkRect = columns->HostWorkRect;
window->DC.CurrentColumns = NULL;
window->DC.ColumnsOffset.x = 0.0f;
- window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+ window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
}
// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
diff --git a/imgui/imstb_textedit.h b/imgui/imstb_textedit.h
index d7fcbd62..2077d02a 100644
--- a/imgui/imstb_textedit.h
+++ b/imgui/imstb_textedit.h
@@ -1,4 +1,4 @@
-// [DEAR IMGUI]
+// [DEAR IMGUI]
// This is a slightly modified version of stb_textedit.h 1.13.
// Those changes would need to be pushed into nothings/stb:
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
diff --git a/imgui/imstb_truetype.h b/imgui/imstb_truetype.h
index c1cdb180..193338af 100644
--- a/imgui/imstb_truetype.h
+++ b/imgui/imstb_truetype.h
@@ -1,4 +1,4 @@
-// [DEAR IMGUI]
+// [DEAR IMGUI]
// This is a slightly modified version of stb_truetype.h 1.20.
// Mostly fixing for compiler and static analyzer warnings.
// Grep for [DEAR IMGUI] to find the changes.