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
diff options
context:
space:
mode:
authorBartosz Taudul <wolf@nereid.pl>2021-05-25 23:21:54 +0300
committerBartosz Taudul <wolf@nereid.pl>2021-05-25 23:21:54 +0300
commit688a9722c70d8e8373ffb901a42b7fd0d842a5f3 (patch)
tree5c2b659ff748bc1457bff9dd834034dc0dbb5a37 /imgui/imgui.cpp
parent4fc02f5680c7ff3499d869f131cf8f8cd50f8cf5 (diff)
Update ImGui to 1.83 + docking.
Diffstat (limited to 'imgui/imgui.cpp')
-rw-r--r--imgui/imgui.cpp797
1 files changed, 480 insertions, 317 deletions
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index 1bf605ad..aad29c78 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.82
+// dear imgui, v1.83
// (main code and documentation)
// Help:
@@ -11,16 +11,16 @@
// - FAQ http://dearimgui.org/faq
// - Homepage & latest https://github.com/ocornut/imgui
// - Releases & changelog https://github.com/ocornut/imgui/releases
-// - Gallery https://github.com/ocornut/imgui/issues/3488 (please post your screenshots/video there!)
+// - Gallery https://github.com/ocornut/imgui/issues/3793 (please post your screenshots/video there!)
+// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
-// - Wiki https://github.com/ocornut/imgui/wiki
// - Issues & support https://github.com/ocornut/imgui/issues
// - Discussions https://github.com/ocornut/imgui/discussions
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
// See LICENSE.txt for copyright and licensing details (standard MIT License).
// This library is free but needs your support to sustain development and maintenance.
-// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.org".
+// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com".
// Individuals: you can support continued development via donations. See docs/README or web page.
// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
@@ -135,17 +135,17 @@ CODE
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.
+ - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)
+ - 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, fewer bugs.
- Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
- The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
- Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
- You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ.
+ You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki.
- Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
- For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI,
+ For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI,
where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
- - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
+ - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
- This codebase is also optimized to yield decent performances with typical "Debug" builds settings.
- Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
If you get an assert, read the messages and comments around the assert.
@@ -158,8 +158,8 @@ CODE
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 as a top-most commit which you can regularly rebase over master.
+ - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h)
+ - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master".
- You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file.
- Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
@@ -174,12 +174,12 @@ CODE
- Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
- In the majority of cases you should be able to use unmodified backends files available in the backends/ folder.
- Add the Dear ImGui source files + selected backend 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).
+ It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL).
- You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.
- When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
- Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
- phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render().
+ phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render().
- Refer to the backends 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.
@@ -187,7 +187,7 @@ CODE
HOW A SIMPLE APPLICATION MAY LOOK LIKE
--------------------------------------
EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder).
- The sub-folders in examples/ contains examples applications following this structure.
+ The sub-folders in examples/ contain examples applications following this structure.
// Application init: create a dear imgui context, setup some options, load fonts
ImGui::CreateContext();
@@ -237,7 +237,7 @@ CODE
unsigned char* pixels = NULL;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
- // At this point you've got the texture data and you need to upload that your your graphic system:
+ // At this point you've got the texture data and you need to upload that to 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 for details about ImTextureID.
MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
@@ -256,7 +256,7 @@ CODE
io.MouseDown[1] = my_mouse_buttons[1];
// Call NewFrame(), after this point you can use ImGui::* functions anytime
- // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere)
+ // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)
ImGui::NewFrame();
// Most of your application code here
@@ -276,14 +276,14 @@ CODE
// Shutdown
ImGui::DestroyContext();
- To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest your application,
+ To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application,
you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
Please read the FAQ and example applications for details about this!
HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
---------------------------------------------
- The backends in impl_impl_XXX.cpp files contains many working implementations of a rendering function.
+ The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function.
void void MyImGuiRenderFunction(ImDrawData* draw_data)
{
@@ -305,11 +305,11 @@ CODE
}
else
{
- // The texture for the draw call is specified by pcmd->TextureId.
+ // The texture for the draw call is specified by pcmd->GetTexID().
// The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
- MyEngineBindTexture((MyTexture*)pcmd->TextureId);
+ MyEngineBindTexture((MyTexture*)pcmd->GetTexID());
- // We are using scissoring to clip some objects. All low-level graphics API should supports it.
+ // We are using scissoring to clip some objects. All low-level graphics API should support it.
// - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
// (some elements visible outside their bounds) but you can fix that once everything else works!
// - Clipping coordinates are provided in imgui coordinates space:
@@ -352,7 +352,7 @@ CODE
Note that io.NavInputs[] is cleared by EndFrame().
- See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
- - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
+ - We use a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
- You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets
- If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo
@@ -364,7 +364,7 @@ CODE
Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved.
When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that.
- (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!)
+ (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse moving back and forth!)
(In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
to set a boolean to ignore your other external mouse positions until the external source is moved again.)
@@ -374,7 +374,7 @@ CODE
Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
- 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.
+ When you are not sure about an 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.
(Docking/Viewport Branch)
@@ -386,6 +386,9 @@ CODE
- 2021/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
+ - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
+ - if you are using official backends from the source tree: you have nothing to do.
+ - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
- 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags.
- ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft
- ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight
@@ -434,7 +437,7 @@ CODE
- 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently).
- 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton.
- 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory.
- - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.
+ - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.
- 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now!
- 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
@@ -443,7 +446,7 @@ CODE
- if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.
- if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
see https://github.com/ocornut/imgui/issues/3361 for all details.
- kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used.
+ kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used.
for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
- obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.
- 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
@@ -463,7 +466,7 @@ CODE
- ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding
- ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
- IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS
- - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was the vaguely documented and rarely if ever used). Instead we added an explicit PrimUnreserve() API.
+ - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API.
- 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it).
- 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.
@@ -491,7 +494,7 @@ CODE
- 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
- 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
- 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
- - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrary small value!
+ - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value!
- 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
- 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
- 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
@@ -586,12 +589,12 @@ CODE
- 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
- 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
- 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
- - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild().
+ - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild().
- 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
- 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/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, 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.
+ 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 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 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.
@@ -599,7 +602,7 @@ CODE
- 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
- 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen).
- 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.
- - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337).
+ - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337).
- 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337)
- 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
- 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert.
@@ -630,7 +633,7 @@ CODE
- 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
- 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount.
- 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence
- - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry!
+ - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry!
- 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
- 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
- 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
@@ -685,7 +688,7 @@ CODE
===========
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++.
+ A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++.
- Run the examples/ and explore them.
- See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
- The demo covers most features of Dear ImGui, so you can read the code and see its output.
@@ -695,7 +698,7 @@ CODE
- The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
- The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
- Your programming IDE is your friend, find the type or function declaration to find comments
- associated to it.
+ associated with it.
Q: What is this library called?
Q: Which version should I get?
@@ -708,15 +711,15 @@ CODE
Q: How to get started?
A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.
- Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application?
+ Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?
A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
- >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this.
+ >> See https://www.dearimgui.org/faq for a fully detailed answer. You really want to read this.
Q. How can I enable keyboard controls?
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 little squares are showing instead of text..
- Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
- Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries..
+ Q: I integrated Dear ImGui in my engine and little squares are showing instead of text...
+ Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...
+ Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...
>> See https://www.dearimgui.org/faq
Q&A: Usage
@@ -754,16 +757,16 @@ CODE
==============
Q: How can I help?
- A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui!
+ A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui!
We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
- This is among the most useful thing you can do for Dear ImGui. With increased funding we can hire more people working on this project.
+ This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people working on this project.
- Individuals: you can support continued development via PayPal donations. See README.
- - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt
+ - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt
and see how you want to help and can help!
- 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/3488). 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).
+ You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers.
+ But even without visuals, disclosing your use of dear imgui helps 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).
*/
@@ -826,6 +829,9 @@ CODE
#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types
#endif
+#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
+#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
+#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
#endif
// Clang/GCC warnings with -Weverything
@@ -868,7 +874,7 @@ static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time
static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend)
-static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow().
+static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow().
static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
@@ -910,8 +916,8 @@ static void NavUpdateInitResult();
static float NavUpdatePageUpPageDown();
static inline void NavUpdateAnyRequestFlag();
static void NavEndFrame();
-static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
-static void NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
+static bool NavScoreItem(ImGuiNavItemData* result, ImRect cand);
+static void NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
static ImVec2 NavCalcPreferredRefPos();
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
@@ -943,7 +949,6 @@ static void UpdateViewportsEndFrame();
static void UpdateSelectWindowViewport(ImGuiWindow* window);
static bool UpdateTryMergeWindowIntoHostViewport(ImGuiWindow* window, ImGuiViewportP* host_viewport);
static bool UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window);
-static void SetCurrentViewport(ImGuiWindow* window, ImGuiViewportP* viewport);
static bool GetWindowAlwaysWantOwnViewport(ImGuiWindow* window);
static int FindPlatformMonitorForPos(const ImVec2& pos);
static int FindPlatformMonitorForRect(const ImRect& r);
@@ -958,7 +963,7 @@ static void UpdateViewportPlatformMonitor(ImGuiViewportP* viewport);
// DLL users:
// - Heaps and globals are not shared across DLL boundaries!
// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from.
-// - Same apply for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanism works without DLL).
+// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL).
// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in).
@@ -971,16 +976,16 @@ static void UpdateViewportPlatformMonitor(ImGuiViewportP* viewport);
// struct ImGuiContext;
// extern thread_local ImGuiContext* MyImGuiTLS;
// #define GImGui MyImGuiTLS
-// And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
-// - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
-// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace.
+// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
+// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
+// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace.
// - DLL users: read comments above.
#ifndef GImGui
ImGuiContext* GImGui = NULL;
#endif
// Memory Allocator functions. Use SetAllocatorFunctions() to change them.
-// - You probably don't want to modify those mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
+// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
// - DLL users: read comments above.
#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
@@ -1102,7 +1107,6 @@ ImGuiIO::ImGuiIO()
// Docking options (when ImGuiConfigFlags_DockingEnable is set)
ConfigDockingNoSplit = false;
- ConfigDockingWithShift = false;
ConfigDockingAlwaysTabBar = false;
ConfigDockingTransparentPayload = false;
@@ -1168,11 +1172,18 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
if (InputQueueSurrogate != 0)
{
if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
+ {
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
- else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang)
- cp = IM_UNICODE_CODEPOINT_INVALID;
+ }
else
+ {
+#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF
+ cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar
+#else
cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
+#endif
+ }
+
InputQueueSurrogate = 0;
}
InputQueueCharacters.push_back(cp);
@@ -3218,7 +3229,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false;
// Test if the item is disabled
- if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
+ if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
// Special handling for calling after Begin() which represent the title bar or tab.
@@ -3244,7 +3255,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
return false;
if (g.NavDisableMouseHover)
return false;
- if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled))
+ if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (g.CurrentItemFlags & ImGuiItemFlags_Disabled))
{
g.HoveredIdDisabled = true;
return false;
@@ -3291,15 +3302,21 @@ void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatu
}
// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
-bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
+void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
{
ImGuiContext& g = *GImGui;
+ IM_ASSERT(id != 0 && id == window->DC.LastItemId);
// Increment counters
- const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
+ // FIXME: ImGuiItemFlags_Disabled should disable more.
+ const bool is_tab_stop = (g.CurrentItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
window->DC.FocusCounterRegular++;
if (is_tab_stop)
+ {
window->DC.FocusCounterTabStop++;
+ if (g.NavId == id)
+ g.NavIdTabCounter = window->DC.FocusCounterTabStop;
+ }
// 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)
@@ -3313,25 +3330,21 @@ bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
if (g.TabFocusRequestCurrWindow == window)
{
if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular)
- return true;
+ {
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
+ return;
+ }
if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
{
g.NavJustTabbedId = id;
- return true;
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
+ return;
}
// If another item is about to be focused, we clear our own active id
if (g.ActiveId == id)
ClearActiveID();
}
-
- return false;
-}
-
-void ImGui::FocusableItemUnregister(ImGuiWindow* window)
-{
- window->DC.FocusCounterRegular--;
- window->DC.FocusCounterTabStop--;
}
float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
@@ -3858,10 +3871,17 @@ void ImGui::UpdateMouseWheel()
// Mouse wheel scrolling
// If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
+ if (g.IO.KeyCtrl)
+ return;
+
+ // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
+ // (we avoid doing it on OSX as it the OS input layer handles this already)
+ const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
+ const float wheel_y = swap_axis ? 0.0f : g.IO.MouseWheel;
+ const float wheel_x = swap_axis ? g.IO.MouseWheel : g.IO.MouseWheelH;
// Vertical Mouse Wheel scrolling
- const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
- if (wheel_y != 0.0f && !g.IO.KeyCtrl)
+ if (wheel_y != 0.0f)
{
StartLockWheelingWindow(window);
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
@@ -3875,8 +3895,7 @@ void ImGui::UpdateMouseWheel()
}
// Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
- const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
- if (wheel_x != 0.0f && !g.IO.KeyCtrl)
+ if (wheel_x != 0.0f)
{
StartLockWheelingWindow(window);
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
@@ -3898,12 +3917,14 @@ void ImGui::UpdateTabFocus()
g.TabFocusPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
if (g.ActiveId == 0 && g.TabFocusPressed)
{
- // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
- // manipulate the Next fields even, even though they will be turned into Curr fields by the code below.
+ // - This path is only taken when no widget are active/tabbed-into yet.
+ // Subsequent tabbing will be processed by FocusableItemRegister()
+ // - Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
+ // manipulate the Next fields here even though they will be turned into Curr fields below.
g.TabFocusRequestNextWindow = g.NavWindow;
g.TabFocusRequestNextCounterRegular = INT_MAX;
if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
- g.TabFocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
+ g.TabFocusRequestNextCounterTabStop = g.NavIdTabCounter + (g.IO.KeyShift ? -1 : 0);
else
g.TabFocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
}
@@ -3930,6 +3951,7 @@ void ImGui::UpdateTabFocus()
void ImGui::UpdateHoveredWindowAndCaptureFlags()
{
ImGuiContext& g = *GImGui;
+ g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));
// Find the window hovered by mouse:
// - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
@@ -4032,7 +4054,8 @@ void ImGui::NewFrame()
g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
- g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
+ g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame));
+ g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX;
UpdateViewportsNewFrame();
@@ -4157,7 +4180,7 @@ void ImGui::NewFrame()
UpdateTabFocus();
// Mark all windows as not visible and compact unused memory.
- IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
+ IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
for (int i = 0; i != g.Windows.Size; i++)
{
@@ -4176,6 +4199,9 @@ void ImGui::NewFrame()
for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
+ for (int i = 0; i < g.TablesTempDataStack.Size; i++)
+ if (g.TablesTempDataStack[i].LastTimeActive >= 0.0f && g.TablesTempDataStack[i].LastTimeActive < memory_compact_start_time)
+ TableGcCompactTransientBuffers(&g.TablesTempDataStack[i]);
if (g.GcCompactAll)
GcCompactTransientMiscBuffers();
g.GcCompactAll = false;
@@ -4189,7 +4215,7 @@ void ImGui::NewFrame()
g.CurrentWindowStack.resize(0);
g.BeginPopupStack.resize(0);
g.ItemFlagsStack.resize(0);
- g.ItemFlagsStack.push_back(ImGuiItemFlags_Default_);
+ g.ItemFlagsStack.push_back(ImGuiItemFlags_None);
g.GroupStack.resize(0);
ClosePopupsOverWindow(g.NavWindow, false);
@@ -4218,20 +4244,20 @@ void ImGui::UpdateDebugToolItemPicker()
if (g.DebugItemPickerActive)
{
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
- ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
- if (ImGui::IsKeyPressedMap(ImGuiKey_Escape))
+ SetMouseCursor(ImGuiMouseCursor_Hand);
+ if (IsKeyPressedMap(ImGuiKey_Escape))
g.DebugItemPickerActive = false;
- if (ImGui::IsMouseClicked(0) && hovered_id)
+ if (IsMouseClicked(0) && hovered_id)
{
g.DebugItemPickerBreakId = hovered_id;
g.DebugItemPickerActive = false;
}
- ImGui::SetNextWindowBgAlpha(0.60f);
- ImGui::BeginTooltip();
- ImGui::Text("HoveredId: 0x%08X", hovered_id);
- ImGui::Text("Press ESC to abort picking.");
- ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
- ImGui::EndTooltip();
+ SetNextWindowBgAlpha(0.60f);
+ BeginTooltip();
+ Text("HoveredId: 0x%08X", hovered_id);
+ Text("Press ESC to abort picking.");
+ TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
+ EndTooltip();
}
}
@@ -4253,10 +4279,8 @@ void ImGui::Initialize(ImGuiContext* context)
g.SettingsHandlers.push_back(ini_handler);
}
-#ifdef IMGUI_HAS_TABLE
// Add .ini handle for ImGuiTable type
TableSettingsInstallHandler(context);
-#endif // #ifdef IMGUI_HAS_TABLE
// Create default viewport
ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
@@ -4340,7 +4364,9 @@ void ImGui::Shutdown(ImGuiContext* context)
g.ShrinkWidthBuffer.clear();
g.Tables.Clear();
- g.CurrentTableStack.clear();
+ for (int i = 0; i < g.TablesTempDataStack.Size; i++)
+ g.TablesTempDataStack[i].~ImGuiTableTempData();
+ g.TablesTempDataStack.clear();
g.DrawChannelsTempMergeBuffer.clear();
g.ClipboardHandlerData.clear();
@@ -4572,7 +4598,7 @@ static void ImGui::EndFrameDrawDimmedBackgrounds()
bb.Expand(-g.FontSize - 1.0f);
rounding = window->WindowRounding;
}
- draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
+ draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, 0, 3.0f);
draw_list->PopClipRect();
}
}
@@ -4698,6 +4724,7 @@ void ImGui::Render()
for (int n = 0; n != g.Windows.Size; n++)
{
ImGuiWindow* window = g.Windows[n];
+ IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
AddRootWindowToDrawData(window);
}
@@ -4785,10 +4812,11 @@ static void FindHoveredWindow()
hovered_window = g.MovingWindow;
ImVec2 padding_regular = g.Style.TouchExtraPadding;
- ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
+ ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular;
for (int i = g.Windows.Size - 1; i >= 0; i--)
{
ImGuiWindow* window = g.Windows[i];
+ IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
if (!window->Active || window->Hidden)
continue;
if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
@@ -4802,7 +4830,7 @@ static void FindHoveredWindow()
if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
bb.Expand(padding_regular);
else
- bb.Expand(padding_for_resize_from_edges);
+ bb.Expand(padding_for_resize);
if (!bb.Contains(g.IO.MousePos))
continue;
@@ -4818,6 +4846,7 @@ static void FindHoveredWindow()
if (hovered_window == NULL)
hovered_window = window;
+ IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindowDockTree != g.MovingWindow->RootWindowDockTree))
hovered_window_ignoring_moving_window = window;
if (hovered_window && hovered_window_ignoring_moving_window)
@@ -5242,7 +5271,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
parent_window->DC.CursorPos = child_window->Pos;
// Process navigation-in immediately so NavInit can run on first frame
- if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
+ if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll))
{
FocusWindow(child_window);
NavInitWindow(child_window, false);
@@ -5289,13 +5318,13 @@ void ImGui::EndChild()
ImGuiWindow* parent_window = g.CurrentWindow;
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
ItemSize(sz);
- if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
+ if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
{
ItemAdd(bb, window->ChildId);
RenderNavHighlight(bb, window->ChildId);
// When browsing a window that has no activable items (scroll only) we keep a highlight on the child
- if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
+ if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow)
RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
}
else
@@ -5407,7 +5436,12 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
}
- g.WindowsFocusOrder.push_back(window);
+ if (!(flags & ImGuiWindowFlags_ChildWindow))
+ {
+ g.WindowsFocusOrder.push_back(window);
+ window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);
+ }
+
if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
g.Windows.push_front(window); // Quite slow but rare and only once
else
@@ -5453,8 +5487,9 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& s
if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
{
ImGuiWindow* window_for_height = GetWindowForTitleAndMenuHeight(window);
+ const float decoration_up_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight();
new_size = ImMax(new_size, g.Style.WindowMinSize);
- new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
+ new_size.y = ImMax(new_size.y, decoration_up_height + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
}
return new_size;
}
@@ -5483,9 +5518,9 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
{
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
- ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight());
+ const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
ImVec2 size_pad = window->WindowPadding * 2.0f;
- ImVec2 size_desired = size_contents + size_pad + size_decorations;
+ ImVec2 size_desired = size_contents + size_pad + ImVec2(0.0f, decoration_up_height);
if (window->Flags & ImGuiWindowFlags_Tooltip)
{
// Tooltip always resize
@@ -5512,8 +5547,8 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
// When the window cannot fit all contents (either because of constraints, either because screen is too small),
// we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
- bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
- bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
+ bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - 0.0f < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
+ bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_up_height < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
if (will_have_scrollbar_x)
size_auto_fit.y += style.ScrollbarSize;
if (will_have_scrollbar_y)
@@ -5555,53 +5590,64 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co
*out_size = size_constrained;
}
+// Data for resizing from corner
struct ImGuiResizeGripDef
{
ImVec2 CornerPosN;
ImVec2 InnerDir;
int AngleMin12, AngleMax12;
};
-
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 (Unused)
- { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }, // Upper-right (Unused)
+ { 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)
};
+// Data for resizing from borders
struct ImGuiResizeBorderDef
{
ImVec2 InnerDir;
- ImVec2 CornerPosN1, CornerPosN2;
+ ImVec2 SegmentN1, SegmentN2;
float OuterAngle;
};
-
static const ImGuiResizeBorderDef resize_border_def[4] =
{
- { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Top
+ { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left
{ ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right
- { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }, // Bottom
- { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f } // Left
+ { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up
+ { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down
};
static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
{
ImRect rect = window->Rect();
- if (thickness == 0.0f) rect.Max -= ImVec2(1, 1);
- if (border_n == 0) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } // Top
- if (border_n == 1) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } // Right
- if (border_n == 2) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } // Bottom
- if (border_n == 3) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } // Left
+ if (thickness == 0.0f)
+ rect.Max -= ImVec2(1, 1);
+ if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); }
+ if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); }
+ if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); }
+ if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); }
IM_ASSERT(0);
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)
+ImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n)
{
- IM_ASSERT(n >= 0 && n <= 7);
+ IM_ASSERT(n >= 0 && n < 4);
+ ImGuiID id = window->DockIsActive ? window->DockNode->HostWindow->ID : window->ID;
+ id = ImHashStr("#RESIZE", 0, id);
+ id = ImHashData(&n, sizeof(int), id);
+ return id;
+}
+
+// Borders (Left, Right, Up, Down)
+ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir)
+{
+ IM_ASSERT(dir >= 0 && dir < 4);
+ int n = (int)dir + 4;
ImGuiID id = window->DockIsActive ? window->DockNode->HostWindow->ID : window->ID;
id = ImHashStr("#RESIZE", 0, id);
id = ImHashData(&n, sizeof(int), id);
@@ -5624,7 +5670,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
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;
+ const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f;
ImVec2 pos_target(FLT_MAX, FLT_MAX);
ImVec2 size_target(FLT_MAX, FLT_MAX);
@@ -5646,15 +5692,16 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
PushID("#RESIZE");
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
{
- const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
- const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
+ const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n];
+ const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN);
// Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
- ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
+ bool hovered, held;
+ ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size);
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(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
+ ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID()
+ ButtonBehavior(resize_rect, resize_grip_id, &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;
@@ -5670,39 +5717,41 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
{
// Resize from any of the four corners
// We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
- ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip
- ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
- ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
+ ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, def.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
+ ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
+ ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip
corner_target = ImClamp(corner_target, clamp_min, clamp_max);
- CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
+ CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);
}
+
+ // Only lower-left grip is visible before hovering/activating
if (resize_grip_n == 0 || held || hovered)
resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
}
for (int border_n = 0; border_n < resize_border_count; border_n++)
{
+ const ImGuiResizeBorderDef& def = resize_border_def[border_n];
+ const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
+
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(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
+ ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);
+ ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
+ ButtonBehavior(border_rect, border_id, &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)
{
- g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
+ g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
if (held)
*border_held = border_n;
}
if (held)
{
+ ImVec2 clamp_min(border_n == ImGuiDir_Right ? visibility_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down ? visibility_rect.Min.y : -FLT_MAX);
+ ImVec2 clamp_max(border_n == ImGuiDir_Left ? visibility_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? visibility_rect.Max.y : +FLT_MAX);
ImVec2 border_target = window->Pos;
- ImVec2 border_posn;
- if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top
- if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right
- if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom
- if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left
- ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX);
- ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX);
+ border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING;
border_target = ImClamp(border_target, clamp_min, clamp_max);
- CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
+ CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);
}
}
PopID();
@@ -5769,8 +5818,8 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
{
const ImGuiResizeBorderDef& def = resize_border_def[border_held];
ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
- window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
- window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
+ window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
+ window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual
}
if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
@@ -5909,7 +5958,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
}
// Render title text, collapse button, close button
-// When inside a dock node, this is handled in DockNodeUpdateTabBar() instead.
+// When inside a dock node, this is handled in DockNodeCalcTabBarLayout() instead.
void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
{
ImGuiContext& g = *GImGui;
@@ -5920,8 +5969,8 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
- const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
- window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
+ const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;
+ g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
// Layout buttons
@@ -5958,7 +6007,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
*p_open = false;
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
- window->DC.ItemFlags = item_flags_backup;
+ g.CurrentItemFlags = item_flags_backup;
// Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
// FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
@@ -6046,14 +6095,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Update the Appearing flag
bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
- const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
if (flags & ImGuiWindowFlags_Popup)
{
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
window_just_activated_by_user |= (window != popup_ref.Window);
}
- window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
+ window->Appearing = window_just_activated_by_user;
if (window->Appearing)
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
@@ -6206,7 +6254,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
// Update contents size from last frame for auto-fitting (or use explicit size)
+ const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);
+
+ // FIXME: These flags are decremented before they are used. This means that in order to have these fields produce their intended behaviors
+ // for one frame we must set them to at least 2, which is counter-intuitive. HiddenFramesCannotSkipItems is a more complicated case because
+ // it has a single usage before this code block and may be set below before it is finally checked.
if (window->HiddenFramesCanSkipItems > 0)
window->HiddenFramesCanSkipItems--;
if (window->HiddenFramesCannotSkipItems > 0)
@@ -6707,8 +6760,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
- window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
- window->DC.NavLayerActiveMaskNext = 0x00;
+ window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext;
+ window->DC.NavLayersActiveMaskNext = 0x00;
window->DC.NavHideHighlightOneFrame = false;
window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
@@ -6773,7 +6826,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
// Docking: Dragging a dockable window (or any of its child) turns it into a drag and drop source.
// We need to do this _before_ we overwrite window->DC.LastItemId below because BeginDockableDragDropSource() also overwrites it.
- if ((g.MovingWindow == window) && (g.IO.ConfigDockingWithShift == g.IO.KeyShift))
+ if (g.MovingWindow == window && g.IO.KeyShift == false)
if ((window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoDocking) == 0)
BeginDockableDragDropSource(window);
@@ -6804,7 +6857,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Pull/inherit current state
- window->DC.ItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack
+ g.CurrentItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack
window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // Inherit from parent only // -V595
if (!(flags & ImGuiWindowFlags_DockNodeHost))
@@ -6917,15 +6970,22 @@ void ImGui::End()
void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
+ IM_ASSERT(window == window->RootWindow);
+
+ const int cur_order = window->FocusOrder;
+ IM_ASSERT(g.WindowsFocusOrder[cur_order] == window);
if (g.WindowsFocusOrder.back() == window)
return;
- for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window
- if (g.WindowsFocusOrder[i] == window)
- {
- memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
- g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window;
- break;
- }
+
+ const int new_order = g.WindowsFocusOrder.Size - 1;
+ for (int n = cur_order; n < new_order; n++)
+ {
+ g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1];
+ g.WindowsFocusOrder[n]->FocusOrder--;
+ IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n);
+ }
+ g.WindowsFocusOrder[new_order] = window;
+ window->FocusOrder = (short)new_order;
}
void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
@@ -7013,18 +7073,13 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
{
ImGuiContext& g = *GImGui;
- int start_idx = g.WindowsFocusOrder.Size - 1;
- if (under_this_window != NULL)
- {
- int under_this_window_idx = FindWindowFocusIndex(under_this_window);
- if (under_this_window_idx != -1)
- start_idx = under_this_window_idx - 1;
- }
+ const int start_idx = ((under_this_window != NULL) ? FindWindowFocusIndex(under_this_window) : g.WindowsFocusOrder.Size) - 1;
for (int i = start_idx; i >= 0; i--)
{
// We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user.
ImGuiWindow* window = g.WindowsFocusOrder[i];
- if (window != ignore_window && window->WasActive && window->RootWindow == window)
+ IM_ASSERT(window == window->RootWindow);
+ if (window != ignore_window && window->WasActive)
if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
{
// FIXME-DOCK: This is failing (lagging by one frame) for docked windows.
@@ -7077,24 +7132,22 @@ void ImGui::PopFont()
void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
{
ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- ImGuiItemFlags item_flags = window->DC.ItemFlags;
+ ImGuiItemFlags item_flags = g.CurrentItemFlags;
IM_ASSERT(item_flags == g.ItemFlagsStack.back());
if (enabled)
item_flags |= option;
else
item_flags &= ~option;
- window->DC.ItemFlags = item_flags;
+ g.CurrentItemFlags = item_flags;
g.ItemFlagsStack.push_back(item_flags);
}
void ImGui::PopItemFlag()
{
ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack.
g.ItemFlagsStack.pop_back();
- window->DC.ItemFlags = g.ItemFlagsStack.back();
+ g.CurrentItemFlags = g.ItemFlagsStack.back();
}
// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
@@ -7570,11 +7623,11 @@ void ImGui::SetItemDefaultFocus()
ImGuiWindow* window = g.CurrentWindow;
if (!window->Appearing)
return;
- if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
+ if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent)
{
g.NavInitRequest = false;
- g.NavInitResultId = g.NavWindow->DC.LastItemId;
- g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
+ g.NavInitResultId = window->DC.LastItemId;
+ g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
NavUpdateAnyRequestFlag();
if (!IsItemVisible())
SetScrollHereY();
@@ -7712,7 +7765,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
ImGuiContext& g = *GImGui;
// Check user IM_ASSERT macro
- // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means you assert macro is incorrectly defined!
+ // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined!
// If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.
// This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)
// #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong!
@@ -7831,13 +7884,11 @@ void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, voi
ImGuiContext& g = *GImGui;
while (g.CurrentWindowStack.Size > 0)
{
-#ifdef IMGUI_HAS_TABLE
while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow))
{
if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name);
EndTable();
}
-#endif
ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT(window != NULL);
while (g.CurrentTabBar != NULL) //-V1044
@@ -8007,7 +8058,7 @@ void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
// Declare item bounding box for clipping and interaction.
// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
-bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
+bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemAddFlags flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -8023,7 +8074,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
// We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
// If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
- window->DC.NavLayerActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
+ window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
if (g.NavId == id || g.NavAnyRequest)
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
@@ -8056,6 +8107,11 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
return false;
//if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
+ // Tab stop handling (previously was using internal ItemFocusable() api)
+ // FIXME-NAV: We would now want to move this above the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343)
+ if (flags & ImGuiItemAddFlags_Focusable)
+ ItemFocusable(window, id);
+
// We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
if (IsMouseHoveringRect(bb.Min, bb.Max))
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
@@ -8436,24 +8492,29 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
ImVec2 scroll = window->Scroll;
if (window->ScrollTarget.x < FLT_MAX)
{
+ float decoration_total_width = window->ScrollbarSizes.x;
float center_x_ratio = window->ScrollTargetCenterRatio.x;
float scroll_target_x = window->ScrollTarget.x;
- float snap_x_min = 0.0f;
- float snap_x_max = window->ScrollMax.x + window->Size.x;
if (window->ScrollTargetEdgeSnapDist.x > 0.0f)
+ {
+ float snap_x_min = 0.0f;
+ float snap_x_max = window->ScrollMax.x + window->SizeFull.x - decoration_total_width;
scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio);
- scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x);
+ }
+ scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - decoration_total_width);
}
if (window->ScrollTarget.y < FLT_MAX)
{
- float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
+ float decoration_total_height = window->TitleBarHeight() + window->MenuBarHeight() + window->ScrollbarSizes.y;
float center_y_ratio = window->ScrollTargetCenterRatio.y;
float scroll_target_y = window->ScrollTarget.y;
- float snap_y_min = 0.0f;
- float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height;
if (window->ScrollTargetEdgeSnapDist.y > 0.0f)
+ {
+ float snap_y_min = 0.0f;
+ float snap_y_max = window->ScrollMax.y + window->SizeFull.y - decoration_total_height;
scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio);
- scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
+ }
+ scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - decoration_total_height);
}
scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f));
scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f));
@@ -8566,7 +8627,8 @@ void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x
void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
{
IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
- local_y -= window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect
+ const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect;
+ local_y -= decoration_up_height;
window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset
window->ScrollTargetCenterRatio.y = center_y_ratio;
window->ScrollTargetEdgeSnapDist.y = 0.0f;
@@ -8589,7 +8651,7 @@ void ImGui::SetScrollHereX(float center_x_ratio)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- float spacing_x = g.Style.ItemSpacing.x;
+ float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x);
float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
@@ -8602,7 +8664,7 @@ void ImGui::SetScrollHereY(float center_y_ratio)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- float spacing_y = g.Style.ItemSpacing.y;
+ float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y);
float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos
@@ -8733,6 +8795,11 @@ void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags);
}
+void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags)
+{
+ OpenPopupEx(id, popup_flags);
+}
+
// Mark popup as open (toggle toward open state).
// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
@@ -8992,10 +9059,21 @@ void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags
}
// This is a helper to handle the simplest case of associating one named popup to one given widget.
-// - You can pass a NULL str_id to use the identifier of the last item.
-// - You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
-// - This is essentially the same as calling OpenPopupOnItemClick() + BeginPopup() but written to avoid
-// computing the ID twice because BeginPopupContextXXX functions may be called very frequently.
+// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id.
+// - To create a popup with a specific identifier, pass it in str_id.
+// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call.
+// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id.
+// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
+// This is essentially the same as:
+// id = str_id ? GetID(str_id) : GetItemID();
+// OpenPopupOnItemClick(str_id);
+// return BeginPopup(id);
+// Which is essentially the same as:
+// id = str_id ? GetID(str_id) : GetItemID();
+// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
+// OpenPopup(id);
+// return BeginPopup(id);
+// The main difference being that this is tweaked to avoid computing the ID twice.
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
{
ImGuiWindow* window = GImGui->CurrentWindow;
@@ -9180,13 +9258,13 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
//-----------------------------------------------------------------------------
// FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked.
-void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
+void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavWindow != NULL);
IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);
g.NavId = id;
- g.NavLayer = (ImGuiNavLayer)nav_layer;
+ g.NavLayer = nav_layer;
g.NavFocusScopeId = focus_scope_id;
g.NavWindow->NavLastIds[nav_layer] = id;
g.NavWindow->NavRectRel[nav_layer] = rect_rel;
@@ -9249,7 +9327,7 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect
}
// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
-static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
+static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -9380,7 +9458,7 @@ static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
return new_best;
}
-static void ImGui::NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
+static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
{
result->Window = window;
result->ID = id;
@@ -9395,7 +9473,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
//if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
// return;
- const ImGuiItemFlags item_flags = window->DC.ItemFlags;
+ const ImGuiItemFlags item_flags = g.CurrentItemFlags;
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
// Process Init Request
@@ -9418,7 +9496,7 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
// FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
{
- ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
+ ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
#if IMGUI_DEBUG_NAV_SCORING
// [DEBUG] Score all items in NavWindow at all times
if (!g.NavMoveRequest)
@@ -9445,7 +9523,6 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con
g.NavLayer = window->DC.NavLayerCurrent;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
g.NavIdIsAlive = true;
- g.NavIdTabCounter = window->DC.FocusCounterTabStop;
window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position)
}
}
@@ -9541,10 +9618,16 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
// FIXME: ChildWindow test here is wrong for docking
ImGuiContext& g = *GImGui;
IM_ASSERT(window == g.NavWindow);
+
+ if (window->Flags & ImGuiWindowFlags_NoNavInputs)
+ {
+ g.NavId = g.NavFocusScopeId = 0;
+ return;
+ }
+
bool init_for_nav = false;
- if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
- if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
- init_for_nav = true;
+ if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
+ init_for_nav = true;
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
if (init_for_nav)
{
@@ -9658,8 +9741,16 @@ static void ImGui::NavUpdate()
io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
if (io.KeyShift)
io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
- if (io.KeyAlt && !io.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu.
+
+ // AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl)
+ // But also even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
+ if (io.KeyAlt && !io.KeyCtrl)
io.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
+
+ // We automatically cancel toggling nav layer when any text has been typed while holding Alt. (See #370)
+ if (io.KeyAlt && !io.KeyCtrl && g.NavWindowingToggleLayer && io.InputQueueCharacters.Size > 0)
+ g.NavWindowingToggleLayer = false;
+
#undef NAV_MAP_KEY
}
memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
@@ -9725,6 +9816,11 @@ static void ImGui::NavUpdate()
if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
ClearActiveID();
}
+ else if (g.NavLayer != ImGuiNavLayer_Main)
+ {
+ // Leave the "menu" layer
+ NavRestoreLayer(ImGuiNavLayer_Main);
+ }
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
{
// Exit child window
@@ -9741,11 +9837,6 @@ static void ImGui::NavUpdate()
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
}
- else if (g.NavLayer != ImGuiNavLayer_Main)
- {
- // Leave the "menu" layer
- NavRestoreLayer(ImGuiNavLayer_Main);
- }
else
{
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
@@ -9835,7 +9926,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 = IM_ROUND(window->CalcFontSize() * 100 * 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 (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
{
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
@@ -9901,6 +9992,7 @@ static void ImGui::NavUpdateInitResult()
return;
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
+ // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
if (g.NavInitRequestFromMove)
@@ -9926,7 +10018,7 @@ static void ImGui::NavUpdateMoveResult()
}
// Select which result to use
- ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
+ ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
// PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
@@ -9993,7 +10085,7 @@ static float ImGui::NavUpdatePageUpPageDown()
const bool end_pressed = IsKeyPressed(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)
+ if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
{
// Fallback manual-scroll when window has no navigable item
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
@@ -10111,13 +10203,13 @@ static void ImGui::NavEndFrame()
}
}
-static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N)
+static int ImGui::FindWindowFocusIndex(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
- for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--)
- if (g.WindowsFocusOrder[i] == window)
- return i;
- return -1;
+ IM_UNUSED(g);
+ int order = window->FocusOrder;
+ IM_ASSERT(g.WindowsFocusOrder[order] == window);
+ return order;
}
static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
@@ -10257,8 +10349,14 @@ static void ImGui::NavUpdateWindowing()
if (apply_focus_window->NavLastIds[0] == 0)
NavInitWindow(apply_focus_window, false);
- // If the window only has a menu layer, select it directly
- if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
+ // If the window has ONLY a menu layer (no main layer), select it directly
+ // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame,
+ // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since
+ // the target window as already been previewed once.
+ // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases,
+ // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask*
+ // won't be valid.
+ if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu))
g.NavLayer = ImGuiNavLayer_Menu;
// Request OS level focus
@@ -10271,10 +10369,12 @@ static void ImGui::NavUpdateWindowing()
// Apply menu/layer toggle
if (apply_toggle_layer && g.NavWindow)
{
+ ClearActiveID();
+
// Move to parent menu if necessary
ImGuiWindow* new_nav_window = g.NavWindow;
while (new_nav_window->ParentWindow
- && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
+ && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
&& (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
&& (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
new_nav_window = new_nav_window->ParentWindow;
@@ -10287,8 +10387,8 @@ static void ImGui::NavUpdateWindowing()
g.NavDisableHighlight = false;
g.NavDisableMouseHover = true;
- // Reinitialize navigation when entering menu bar with the Alt key. We make it persist on Docking Tab Bars.
- const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
+ // Reinitialize navigation when entering menu bar with the Alt key.
+ const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
const bool preserve_layer_1_nav_id = (new_nav_window->DockNodeAsHost != NULL);
if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id)
g.NavWindow->NavLastIds[new_nav_layer] = 0;
@@ -10327,6 +10427,7 @@ void ImGui::NavUpdateWindowingOverlay()
for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
{
ImGuiWindow* window = g.WindowsFocusOrder[n];
+ IM_ASSERT(window != NULL); // Fix static analyzers
if (!IsWindowNavFocusable(window))
continue;
const char* label = window->Name;
@@ -11514,10 +11615,10 @@ static void ImGui::UpdateViewportsNewFrame()
// Update/copy monitor info
UpdateViewportPlatformMonitor(viewport);
- // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again.
- viewport->WorkOffsetMin = viewport->CurrWorkOffsetMin;
- viewport->WorkOffsetMax = viewport->CurrWorkOffsetMax;
- viewport->CurrWorkOffsetMin = viewport->CurrWorkOffsetMax = ImVec2(0.0f, 0.0f);
+ // Lock down space taken by menu bars and status bars, reset the offset for functions like BeginMainMenuBar() to alter them again.
+ viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin;
+ viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax;
+ viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f);
viewport->UpdateWorkRect();
// Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back.
@@ -11607,6 +11708,7 @@ static void ImGui::UpdateViewportsNewFrame()
// - when releasing a moving window we will revert to aiming behind (at viewport_hovered)
// - when we are between viewports, our dragged preview will tend to show in the last viewport _even_ if we don't have tooltips in their viewports (when lacking monitor info)
// - consider the case of holding on a menu item to browse child menus: even thou a mouse button is held, there's no active id because menu items only react on mouse release.
+ // FIXME-VIEWPORT: This is essentially broken, when ImGuiBackendFlags_HasMouseHoveredViewport is set we want to trust when viewport_hovered==NULL and use that.
const bool is_mouse_dragging_with_an_expected_destination = g.DragDropActive;
if (is_mouse_dragging_with_an_expected_destination && viewport_hovered == NULL)
viewport_hovered = g.MouseLastHoveredViewport;
@@ -12047,7 +12149,7 @@ const ImGuiPlatformMonitor* ImGui::GetViewportPlatformMonitor(ImGuiViewport* vie
ImGuiContext& g = *GImGui;
ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)viewport_p;
int monitor_idx = viewport->PlatformMonitor;
- if (monitor_idx >= 0 || monitor_idx < g.PlatformIO.Monitors.Size)
+ if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size)
return &g.PlatformIO.Monitors[monitor_idx];
return &g.FallbackMonitor;
}
@@ -12260,7 +12362,7 @@ namespace ImGui
static bool DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* payload_window);
static void DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, ImGuiDockPreviewData* preview_data, bool is_explicit_target, bool is_outer_docking);
static void DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, const ImGuiDockPreviewData* preview_data);
- static void DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos);
+ static void DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos, ImVec2* out_close_button_pos);
static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired);
static bool DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking, ImVec2* test_mouse_pos);
static const char* DockNodeGetHostWindowTitle(ImGuiDockNode* node, char* buf, int buf_size) { ImFormatString(buf, buf_size, "##DockNode_%02X", node->ID); return buf; }
@@ -12730,7 +12832,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
ImGuiDir split_dir = req->DockSplitDir;
if (split_dir != ImGuiDir_None)
{
- // Split into one, one side will be our payload node unless we are dropping a loose window
+ // Split into two, one side will be our payload node unless we are dropping a loose window
const ImGuiAxis split_axis = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
const int split_inheritor_child_idx = (split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0; // Current contents will be moved to the opposite side
const float split_ratio = req->DockSplitRatio;
@@ -12815,6 +12917,29 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
MarkIniSettingsDirty();
}
+// Problem:
+// Undocking a large (~full screen) window would leave it so large that the bottom right sizing corner would more
+// than likely be off the screen and the window would be hard to resize to fit on screen. This can be particularly problematic
+// with 'ConfigWindowsMoveFromTitleBarOnly=true' and/or with 'ConfigWindowsResizeFromEdges=false' as well (the later can be
+// due to missing ImGuiBackendFlags_HasMouseCursors backend flag).
+// Solution:
+// When undocking a window we currently force its maximum size to 90% of the host viewport or monitor.
+// Reevaluate this when we implement preserving docked/undocked size ("docking_wip/undocked_size" branch).
+static ImVec2 FixLargeWindowsWhenUndocking(const ImVec2& size, ImGuiViewport* ref_viewport)
+{
+ if (ref_viewport == NULL)
+ return size;
+
+ ImGuiContext& g = *GImGui;
+ ImVec2 max_size = ImFloor(ref_viewport->WorkSize * 0.90f);
+ if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable)
+ {
+ const ImGuiPlatformMonitor* monitor = ImGui::GetViewportPlatformMonitor(ref_viewport);
+ max_size = ImFloor(monitor->WorkSize * 0.90f);
+ }
+ return ImMin(size, max_size);
+}
+
void ImGui::DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref)
{
IMGUI_DEBUG_LOG_DOCKING("DockContextProcessUndockWindow window '%s', clear_persistent_docking_ref = %d\n", window->Name, clear_persistent_docking_ref);
@@ -12826,6 +12951,8 @@ void ImGui::DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* windo
window->Collapsed = false;
window->DockIsActive = false;
window->DockTabIsVisible = false;
+ window->Size = window->SizeFull = FixLargeWindowsWhenUndocking(window->SizeFull, window->Viewport);
+
MarkIniSettingsDirty();
}
@@ -12839,6 +12966,9 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
{
// In the case of a root node or central node, the node will have to stay in place. Create a new node to receive the payload.
ImGuiDockNode* new_node = DockContextAddNode(ctx, 0);
+ new_node->Pos = node->Pos;
+ new_node->Size = node->Size;
+ new_node->SizeRef = node->SizeRef;
DockNodeMoveWindows(new_node, node);
DockSettingsRenameNodeReferences(node->ID, new_node->ID);
for (int n = 0; n < new_node->Windows.Size; n++)
@@ -12847,7 +12977,7 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
}
else
{
- // Otherwise extract our node and merging our sibling back into the parent node.
+ // Otherwise extract our node and merge our sibling back into the parent node.
IM_ASSERT(node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node);
int index_in_parent = (node->ParentNode->ChildNodes[0] == node) ? 0 : 1;
node->ParentNode->ChildNodes[index_in_parent] = NULL;
@@ -12855,7 +12985,8 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
node->ParentNode->AuthorityForViewport = ImGuiDataAuthority_Window; // The node that stays in place keeps the viewport, so our newly dragged out node will create a new viewport
node->ParentNode = NULL;
}
- node->AuthorityForPos = node->AuthorityForSize = ImGuiDataAuthority_Window;
+ node->AuthorityForPos = node->AuthorityForSize = ImGuiDataAuthority_DockNode;
+ node->Size = FixLargeWindowsWhenUndocking(node->Size, node->Windows[0]->Viewport);
node->WantMouseMove = true;
MarkIniSettingsDirty();
}
@@ -12863,20 +12994,16 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
// This is mostly used for automation.
bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos)
{
- if (split_outer)
- {
- IM_ASSERT(0);
- }
- else
- {
- ImGuiDockPreviewData split_data;
- DockNodePreviewDockSetup(target, target_node, payload, &split_data, false, split_outer);
- if (split_data.DropRectsDraw[split_dir+1].IsInverted())
- return false;
- *out_pos = split_data.DropRectsDraw[split_dir+1].GetCenter();
- return true;
- }
- return false;
+ // In DockNodePreviewDockSetup() for a root central node instead of showing both "inner" and "outer" drop rects
+ // (which would be functionally identical) we only show the outer one. Reflect this here.
+ if (target_node && target_node->ParentNode == NULL && target_node->IsCentralNode() && split_dir != ImGuiDir_None)
+ split_outer = true;
+ ImGuiDockPreviewData split_data;
+ DockNodePreviewDockSetup(target, target_node, payload, &split_data, false, split_outer);
+ if (split_data.DropRectsDraw[split_dir+1].IsInverted())
+ return false;
+ *out_pos = split_data.DropRectsDraw[split_dir+1].GetCenter();
+ return true;
}
//-----------------------------------------------------------------------------
@@ -12950,6 +13077,12 @@ int ImGui::DockNodeGetTabOrder(ImGuiWindow* window)
return tab ? tab_bar->GetTabOrder(tab) : -1;
}
+static void DockNodeHideWindowDuringHostWindowCreation(ImGuiWindow* window)
+{
+ window->Hidden = true;
+ window->HiddenFramesCanSkipItems = window->Active ? 1 : 2;
+}
+
static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar)
{
ImGuiContext& g = *GImGui; (void)g;
@@ -12962,6 +13095,12 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b
IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL);
IMGUI_DEBUG_LOG_DOCKING("DockNodeAddWindow node 0x%08X window '%s'\n", node->ID, window->Name);
+ // If more than 2 windows appeared on the same frame leading to the creation of a new hosting window,
+ // we'll hide windows until the host window is ready. Hide the 1st window after its been output (so it is not visible for one frame).
+ // We will call DockNodeHideWindowDuringHostWindowCreation() on ourselves in Begin()
+ if (node->HostWindow == NULL && node->Windows.Size == 1 && node->Windows[0]->WasActive == false)
+ DockNodeHideWindowDuringHostWindowCreation(node->Windows[0]);
+
node->Windows.push_back(window);
node->WantHiddenTabBarUpdate = true;
window->DockNode = node;
@@ -12969,14 +13108,6 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b
window->DockIsActive = (node->Windows.Size > 1);
window->DockTabWantClose = false;
- // If more than 2 windows appeared on the same frame, we'll create a new hosting DockNode from the point of the second window submission.
- // Then we need to hide the first window (after its been output) otherwise it would be visible as a standalone window for one frame.
- if (node->HostWindow == NULL && node->Windows.Size == 2 && node->Windows[0]->WasActive == false)
- {
- node->Windows[0]->Hidden = true;
- node->Windows[0]->HiddenFramesCanSkipItems = 1;
- }
-
// When reactivating a node with one or two loose window, the window pos/size/viewport are authoritative over the node storage.
// In particular it is important we init the viewport from the first window so we don't create two viewports and drop one.
if (node->HostWindow == NULL && node->IsFloatingNode())
@@ -13522,10 +13653,10 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
ImGuiDockNode* root_node = DockNodeGetRootNode(central_node);
ImRect root_rect(root_node->Pos, root_node->Pos + root_node->Size);
ImRect hole_rect(central_node->Pos, central_node->Pos + central_node->Size);
- if (hole_rect.Min.x > root_rect.Min.x) { hole_rect.Min.x += WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS; }
- if (hole_rect.Max.x < root_rect.Max.x) { hole_rect.Max.x -= WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS; }
- if (hole_rect.Min.y > root_rect.Min.y) { hole_rect.Min.y += WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS; }
- if (hole_rect.Max.y < root_rect.Max.y) { hole_rect.Max.y -= WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS; }
+ if (hole_rect.Min.x > root_rect.Min.x) { hole_rect.Min.x += WINDOWS_HOVER_PADDING; }
+ if (hole_rect.Max.x < root_rect.Max.x) { hole_rect.Max.x -= WINDOWS_HOVER_PADDING; }
+ if (hole_rect.Min.y > root_rect.Min.y) { hole_rect.Min.y += WINDOWS_HOVER_PADDING; }
+ if (hole_rect.Max.y < root_rect.Max.y) { hole_rect.Max.y -= WINDOWS_HOVER_PADDING; }
//GetForegroundDrawList()->AddRect(hole_rect.Min, hole_rect.Max, IM_COL32(255, 0, 0, 255));
if (central_node_hole && !hole_rect.IsInverted())
{
@@ -13742,15 +13873,14 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Layout
ImRect title_bar_rect, tab_bar_rect;
ImVec2 window_menu_button_pos;
- DockNodeCalcTabBarLayout(node, &title_bar_rect, &tab_bar_rect, &window_menu_button_pos);
+ ImVec2 close_button_pos;
+ DockNodeCalcTabBarLayout(node, &title_bar_rect, &tab_bar_rect, &window_menu_button_pos, &close_button_pos);
- // Submit new tabs and apply NavWindow focus back to the tab bar. They will be added as Unsorted and sorted below based on relative DockOrder value.
+ // Submit new tabs, they will be added as Unsorted and sorted below based on relative DockOrder value.
const int tabs_count_old = tab_bar->Tabs.Size;
for (int window_n = 0; window_n < node->Windows.Size; window_n++)
{
ImGuiWindow* window = node->Windows[window_n];
- if (g.NavWindow && g.NavWindow->RootWindow == window)
- tab_bar->SelectedTabId = window->ID;
if (TabBarFindTabByID(tab_bar, window->ID) == NULL)
TabBarAddTab(tab_bar, ImGuiTabItemFlags_Unsorted, window);
}
@@ -13764,7 +13894,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Docking/Collapse button
if (has_window_menu_button)
{
- if (CollapseButton(host_window->GetID("#COLLAPSE"), window_menu_button_pos, node))
+ if (CollapseButton(host_window->GetID("#COLLAPSE"), window_menu_button_pos, node)) // == DockNodeGetWindowMenuButtonId(node)
OpenPopup("#WindowMenu");
if (IsItemActive())
focus_tab_id = tab_bar->SelectedTabId;
@@ -13787,6 +13917,10 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
ImQsort(tab_bar->Tabs.Data + tabs_unsorted_start, tab_bar->Tabs.Size - tabs_unsorted_start, sizeof(ImGuiTabItem), TabItemComparerByDockOrder);
}
+ // Apply NavWindow focus back to the tab bar
+ if (g.NavWindow && g.NavWindow->RootWindow->DockNode == node)
+ tab_bar->SelectedTabId = g.NavWindow->RootWindow->ID;
+
// Selected newly added tabs, or persistent tab ID if the tab bar was just recreated
if (tab_bar_is_recreated && TabBarFindTabByID(tab_bar, node->SelectedTabId) != NULL)
tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = node->SelectedTabId;
@@ -13838,7 +13972,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
window->DockTabItemRect = host_window->DC.LastItemRect;
// Update navigation ID on menu layer
- if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0)
+ if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0)
host_window->NavLastIds[1] = window->ID;
}
}
@@ -13864,8 +13998,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
PushItemFlag(ImGuiItemFlags_Disabled, true);
PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_Text] * ImVec4(1.0f,1.0f,1.0f,0.4f));
}
- const float button_sz = g.FontSize;
- if (CloseButton(host_window->GetID("#CLOSE"), title_bar_rect.GetTR() + ImVec2(-style.FramePadding.x * 2.0f - button_sz, 0.0f)))
+ if (CloseButton(host_window->GetID("#CLOSE"), close_button_pos))
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->VisibleTabId))
{
node->WantCloseTabId = tab->ID;
@@ -13983,27 +14116,35 @@ static bool ImGui::DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow*
}
// window menu button == collapse button when not in a dock node.
-// FIXME: This is similar to RenderWindowTitleBarContents, may want to share code.
-static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos)
+// FIXME: This is similar to RenderWindowTitleBarContents(), may want to share code.
+static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos, ImVec2* out_close_button_pos)
{
ImGuiContext& g = *GImGui;
+ ImGuiStyle& style = g.Style;
+
ImRect r = ImRect(node->Pos.x, node->Pos.y, node->Pos.x + node->Size.x, node->Pos.y + g.FontSize + g.Style.FramePadding.y * 2.0f);
if (out_title_rect) { *out_title_rect = r; }
+ r.Min.x += style.WindowBorderSize;
+ r.Max.x -= style.WindowBorderSize;
+
+ float button_sz = g.FontSize;
+
ImVec2 window_menu_button_pos = r.Min;
- r.Min.x += g.Style.FramePadding.x;
- r.Max.x -= g.Style.FramePadding.x;
+ r.Min.x += style.FramePadding.x;
+ r.Max.x -= style.FramePadding.x;
if (node->HasCloseButton)
{
- r.Max.x -= g.FontSize;// +1.0f; // In DockNodeUpdateTabBar() we currently display a disabled close button even if there is none.
+ r.Max.x -= button_sz;
+ if (out_close_button_pos) *out_close_button_pos = ImVec2(r.Max.x - style.FramePadding.x, r.Min.y);
}
- if (node->HasWindowMenuButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Left)
+ if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Left)
{
- r.Min.x += g.FontSize; // + g.Style.ItemInnerSpacing.x; // <-- Adding ItemInnerSpacing makes the title text moves slightly when in a docking tab bar. Instead we adjusted RenderArrowDockMenu()
+ r.Min.x += button_sz + style.ItemInnerSpacing.x;
}
- else if (node->HasWindowMenuButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Right)
+ else if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Right)
{
- r.Max.x -= g.FontSize + g.Style.FramePadding.x;
+ r.Max.x -= button_sz + style.FramePadding.x;
window_menu_button_pos = ImVec2(r.Max.x, r.Min.y);
}
if (out_tab_bar_rect) { *out_tab_bar_rect = r; }
@@ -14158,9 +14299,9 @@ static void ImGui::DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockN
}
}
- // When docking without holding Shift, we only allow and preview docking when hovering over a drop rect or over the title bar
+ // We only allow and preview docking when hovering over a drop rect or over the title bar
data->IsDropAllowed = (data->SplitDir != ImGuiDir_None) || (data->IsCenterAvailable);
- if (!is_explicit_target && !data->IsSplitDirExplicit && !g.IO.ConfigDockingWithShift)
+ if (!is_explicit_target && !data->IsSplitDirExplicit)
data->IsDropAllowed = false;
// Calculate split area
@@ -14220,7 +14361,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
{
// Compute target tab bar geometry so we can locate our preview tabs
ImRect tab_bar_rect;
- DockNodeCalcTabBarLayout(&data->FutureNode, NULL, &tab_bar_rect, NULL);
+ DockNodeCalcTabBarLayout(&data->FutureNode, NULL, &tab_bar_rect, NULL, NULL);
ImVec2 tab_pos = tab_bar_rect.Min;
if (host_node && host_node->TabBar)
{
@@ -14562,7 +14703,7 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node)
float cur_size_1 = child_1->Size[axis];
float min_size_0 = resize_limits[0] - child_0->Pos[axis];
float min_size_1 = child_1->Pos[axis] + child_1->Size[axis] - resize_limits[1];
- if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER))
+ if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, WINDOWS_HOVER_PADDING, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER))
{
if (touching_nodes[0].Size > 0 && touching_nodes[1].Size > 0)
{
@@ -14688,13 +14829,13 @@ void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond)
// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a CentralNode by default.
// The Central Node is always displayed even when empty and shrink/extend according to the requested size of its neighbors.
// DockSpace() needs to be submitted _before_ any window they can host. If you use a dockspace, submit it early in your app.
-void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags flags, const ImGuiWindowClass* window_class)
+ImGuiID ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags flags, const ImGuiWindowClass* window_class)
{
ImGuiContext* ctx = GImGui;
ImGuiContext& g = *ctx;
ImGuiWindow* window = GetCurrentWindow();
if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable))
- return;
+ return 0;
// Early out if parent window is hidden/collapsed
// This is faster but also DockNodeUpdateTabBar() relies on TabBarLayout() running (which won't if SkipItems=true) to set NextSelectedTabId = 0). See #2960.
@@ -14722,7 +14863,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags fla
{
IM_ASSERT(node->IsDockSpace() == false && "Cannot call DockSpace() twice a frame with the same ID");
node->LocalFlags |= ImGuiDockNodeFlags_DockSpace;
- return;
+ return id;
}
node->LocalFlags |= ImGuiDockNodeFlags_DockSpace;
@@ -14730,7 +14871,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags fla
if (flags & ImGuiDockNodeFlags_KeepAliveOnly)
{
node->LastFrameAlive = g.FrameCount;
- return;
+ return id;
}
const ImVec2 content_avail = GetContentRegionAvail();
@@ -14747,22 +14888,19 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags fla
SetNextWindowSize(node->Size);
g.NextWindowData.PosUndock = false;
- // FIXME-DOCK Why do we need a child window to host a dockspace, could we host it in the existing window?
+ // FIXME-DOCK: Why do we need a child window to host a dockspace, could we host it in the existing window?
+ // FIXME-DOCK: What is the reason for not simply calling BeginChild()? (OK to have a reason but should be commented)
ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_DockNodeHost;
window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar;
window_flags |= ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
+ window_flags |= ImGuiWindowFlags_NoBackground;
char title[256];
ImFormatString(title, IM_ARRAYSIZE(title), "%s/DockSpace_%08X", window->Name, id);
- // FIXME-DOCK: What is the reason for not simply calling BeginChild()?
- if (node->Windows.Size > 0 || node->IsSplitNode())
- PushStyleColor(ImGuiCol_ChildBg, IM_COL32(0, 0, 0, 0));
PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f);
Begin(title, NULL, window_flags);
PopStyleVar();
- if (node->Windows.Size > 0 || node->IsSplitNode())
- PopStyleColor();
ImGuiWindow* host_window = g.CurrentWindow;
host_window->DockNodeAsHost = node;
@@ -14786,6 +14924,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags fla
End();
ItemSize(size);
+ return id;
}
// Tips: Use with ImGuiDockNodeFlags_PassthruCentralNode!
@@ -15373,6 +15512,8 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
{
window->DockIsActive = (node->State == ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing);
window->DockTabIsVisible = false;
+ if (node->Windows.Size > 1)
+ DockNodeHideWindowDuringHostWindowCreation(window);
return;
}
@@ -15410,9 +15551,9 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
else
window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed!
- // Save new dock order only if the tab bar has been visible once.
+ // Save new dock order only if the window has been visible once already
// This allows multiple windows to be created in the same frame and have their respective dock orders preserved.
- if (node->TabBar && node->TabBar->CurrFrameVisible != -1)
+ if (node->TabBar && window->WasActive)
window->DockOrder = (short)DockNodeGetTabOrder(window);
if ((node->WantCloseAll || node->WantCloseTabId == window->ID) && p_open != NULL)
@@ -15432,7 +15573,7 @@ void ImGui::BeginDockableDragDropSource(ImGuiWindow* window)
window->DC.LastItemId = window->MoveId;
window = window->RootWindowDockTree;
IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
- bool is_drag_docking = (g.IO.ConfigDockingWithShift) || ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset);
+ bool is_drag_docking = ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset); // FIXME-DOCKING: Need to make this stateful and explicit
if (is_drag_docking && BeginDragDropSource(ImGuiDragDropFlags_SourceNoPreviewTooltip | ImGuiDragDropFlags_SourceNoHoldToOpenOthers | ImGuiDragDropFlags_SourceAutoExpirePayload))
{
SetDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, &window, sizeof(window));
@@ -15493,7 +15634,7 @@ void ImGui::BeginDockableDragDropTarget(ImGuiWindow* window)
}
const ImRect explicit_target_rect = (node && node->TabBar && !node->IsHiddenTabBar() && !node->IsNoTabBar()) ? node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight()));
- const bool is_explicit_target = g.IO.ConfigDockingWithShift || IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max);
+ const bool is_explicit_target = IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max);
// Preview docking request and find out split direction/ratio
//const bool do_preview = true; // Ignore testing for payload->IsPreview() which removes one frame of delay, but breaks overlapping drop targets within the same window.
@@ -15975,6 +16116,10 @@ static void MetricsHelpMarker(const char* desc)
}
}
+#ifndef IMGUI_DISABLE_DEMO_WINDOWS
+namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); }
+#endif
+
void ImGui::ShowMetricsWindow(bool* p_open)
{
if (!Begin("Dear ImGui Metrics/Debugger", p_open))
@@ -16200,19 +16345,32 @@ void ImGui::ShowMetricsWindow(bool* p_open)
if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
{
for (int n = 0; n < g.TabBars.GetSize(); n++)
- DebugNodeTabBar(g.TabBars.GetByIndex(n), "TabBar");
+ {
+ ImGuiTabBar* tab_bar = g.TabBars.GetByIndex(n);
+ PushID(tab_bar);
+ DebugNodeTabBar(tab_bar, "TabBar");
+ PopID();
+ }
TreePop();
}
// Details for Tables
-#ifdef IMGUI_HAS_TABLE
if (TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
{
for (int n = 0; n < g.Tables.GetSize(); n++)
DebugNodeTable(g.Tables.GetByIndex(n));
TreePop();
}
-#endif // #ifdef IMGUI_HAS_TABLE
+
+ // Details for Fonts
+#ifndef IMGUI_DISABLE_DEMO_WINDOWS
+ ImFontAtlas* atlas = g.IO.Fonts;
+ if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size))
+ {
+ ShowFontAtlas(atlas);
+ TreePop();
+ }
+#endif
// Details for Docking
#ifdef IMGUI_HAS_DOCK
@@ -16263,14 +16421,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
TreePop();
}
-#ifdef IMGUI_HAS_TABLE
if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
{
for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
DebugNodeTableSettings(settings);
TreePop();
}
-#endif // #ifdef IMGUI_HAS_TABLE
#ifdef IMGUI_HAS_DOCK
if (TreeNode("SettingsDocking", "Settings packed data: Docking"))
@@ -16309,7 +16465,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Misc Details
if (TreeNode("Internal state"))
{
- const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
+ const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
Text("WINDOWING");
Indent();
@@ -16369,7 +16525,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
}
-#ifdef IMGUI_HAS_TABLE
// Overlay: Display Tables Rectangles
if (cfg->ShowTablesRects)
{
@@ -16396,7 +16551,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
}
}
-#endif // #ifdef IMGUI_HAS_TABLE
#ifdef IMGUI_HAS_DOCK
// Overlay: Display Docking info
@@ -16642,7 +16796,7 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
}
p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } ");
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
- bool open = TreeNode(tab_bar, "%s", buf);
+ bool open = TreeNode(label, "%s", buf);
if (!is_active) { PopStyleColor(); }
if (is_active && IsItemHovered())
{
@@ -16732,21 +16886,30 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
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" : "");
BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
- BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
- BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
- if (!window->NavRectRel[0].IsInverted())
- BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
- else
- BulletText("NavRectRel[0]: <None>");
+ for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
+ {
+ ImRect r = window->NavRectRel[layer];
+ if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y)
+ {
+ BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]);
+ continue;
+ }
+ BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);
+ if (IsItemHovered())
+ GetForegroundDrawList(window)->AddRect(r.Min + window->Pos, r.Max + window->Pos, IM_COL32(255, 255, 0, 255));
+ }
+ BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
+
BulletText("Viewport: %d%s, ViewportId: 0x%08X, ViewportPos: (%.1f,%.1f)", window->Viewport ? window->Viewport->Idx : -1, window->ViewportOwned ? " (Owned)" : "", window->ViewportId, window->ViewportPos.x, window->ViewportPos.y);
BulletText("ViewportMonitor: %d", window->Viewport ? window->Viewport->PlatformMonitor : -1);
BulletText("DockId: 0x%04X, DockOrder: %d, Act: %d, Vis: %d", window->DockId, window->DockOrder, window->DockIsActive, window->DockTabIsVisible);
if (window->DockNode || window->DockNodeAsHost)
DebugNodeDockNode(window->DockNodeAsHost ? window->DockNodeAsHost : window->DockNode, window->DockNodeAsHost ? "DockNodeAsHost" : "DockNode");
- if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
+
+ if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
if (window->RootWindowDockTree != window->RootWindow) { DebugNodeWindow(window->RootWindowDockTree, "RootWindowDockTree"); }
- if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
- if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
+ if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
+ if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
{
for (int n = 0; n < window->ColumnsStorage.Size; n++)