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.pld@gmail.com>2019-06-12 23:53:23 +0300
committerBartosz Taudul <wolf.pld@gmail.com>2019-06-12 23:53:23 +0300
commit796ca57067d08add10cee93f8110947084e370bc (patch)
treeb8419f9f9978524231fef5f4eb9bfc69bdf9e6c7 /imgui/imgui.cpp
parentd3e0163dd4a3b087f113fb5de58179d54f4712a2 (diff)
Update imgui to 1.71.
Diffstat (limited to 'imgui/imgui.cpp')
-rw-r--r--imgui/imgui.cpp1193
1 files changed, 763 insertions, 430 deletions
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index 0bcaee50..72ea25e7 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.70
+// dear imgui, v1.71
// (main code and documentation)
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
@@ -51,7 +51,7 @@ DOCUMENTATION
- How can I load multiple fonts?
- How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
- How can I interact with standard C++ types (such as std::string and std::vector)?
- - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
+ - How can I use the drawing facilities without a Dear ImGui window? (using ImDrawList API)
- How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad)
- I integrated Dear ImGui in my engine and the text or lines are blurry..
- I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
@@ -172,7 +172,7 @@ CODE
- Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
- Add the Dear ImGui source files to your projects or using your preferred build system.
It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL).
- - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating imgui types with your own maths types.
+ - 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"
@@ -251,16 +251,16 @@ 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 imgui everywhere)
+ // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere)
ImGui::NewFrame();
// Most of your application code here
ImGui::Text("Hello, world!");
- MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
- MyGameRender(); // may use any ImGui functions as well!
+ MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
+ MyGameRender(); // may use any Dear ImGui functions as well!
- // Render imgui, swap buffers
- // (You want to try calling EndFrame/Render as late as you can, to be able to use imgui in your own game rendering code)
+ // Render dear imgui, swap buffers
+ // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)
ImGui::EndFrame();
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
@@ -282,8 +282,8 @@ CODE
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
- const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui
- const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui
+ const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui
+ const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
@@ -294,7 +294,7 @@ CODE
else
{
// The texture for the draw call is specified by pcmd->TextureId.
- // The vast majority of draw calls will use the imgui texture atlas, which value you have set yourself during initialization.
+ // 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);
// We are using scissoring to clip some objects. All low-level graphics API should supports it.
@@ -319,8 +319,8 @@ CODE
- The examples/ folders contains many actual implementation of the pseudo-codes above.
- When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
- They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs
- from the rest of your application. In every cases you need to pass on the inputs to imgui. Refer to the FAQ for more information.
+ They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the
+ rest of your application. In every cases you need to pass on the inputs to Dear ImGui. Refer to the FAQ for more information.
- Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues!
USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
@@ -369,6 +369,12 @@ CODE
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
+ - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have
+ overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering.
+ This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows.
+ Please reach out if you are affected.
+ - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
+ - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
- 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.
- 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).
@@ -593,7 +599,7 @@ CODE
longer name "Dear ImGui" that people can use to refer to this specific library.
Please try to refer to this library as "Dear ImGui".
- Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
+ Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
- When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application.
@@ -993,7 +999,7 @@ CODE
#endif
// Clang/GCC warnings with -Weverything
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great!
#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
@@ -1075,8 +1081,10 @@ static int FindWindowFocusIndex(ImGuiWindow* window);
// Misc
static void UpdateMouseInputs();
static void UpdateMouseWheel();
-static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
-static void RenderOuterBorders(ImGuiWindow* window);
+static bool UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
+static void RenderWindowOuterBorders(ImGuiWindow* window);
+static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
+static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
}
@@ -1129,6 +1137,7 @@ ImGuiStyle::ImGuiStyle()
WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
WindowMinSize = ImVec2(32,32); // Minimum window size
WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
+ WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
@@ -1140,8 +1149,8 @@ ImGuiStyle::ImGuiStyle()
ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
- ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
- ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
+ ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
+ ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
@@ -1249,9 +1258,10 @@ ImGuiIO::ImGuiIO()
// Pass in translated ASCII characters for text input.
// - with glfw you can get those from the callback set in glfwSetCharCallback()
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
-void ImGuiIO::AddInputCharacter(ImWchar c)
+void ImGuiIO::AddInputCharacter(unsigned int c)
{
- InputQueueCharacters.push_back(c);
+ if (c > 0 && c < 0x10000)
+ InputQueueCharacters.push_back((ImWchar)c);
}
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
@@ -1260,7 +1270,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{
unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
- if (c > 0 && c <= 0xFFFF)
+ if (c > 0 && c < 0x10000)
InputQueueCharacters.push_back((ImWchar)c);
}
}
@@ -2412,6 +2422,60 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons
LogRenderedText(&pos_min, text, text_display_end);
}
+
+// Another overly complex function until we reorganize everything into a nice all-in-one helper.
+// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
+// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
+void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
+{
+ ImGuiContext& g = *GImGui;
+ if (text_end_full == NULL)
+ text_end_full = FindRenderedTextEnd(text);
+ const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
+
+ if (text_size.x > pos_max.x - pos_min.x)
+ {
+ // Hello wo...
+ // | | |
+ // min max ellipsis_max
+ // <-> this is generally some padding value
+
+ // FIXME-STYLE: RenderPixelEllipsis() style should use actual font data.
+ const ImFont* font = draw_list->_Data->Font;
+ const float font_size = draw_list->_Data->FontSize;
+ const int ellipsis_dot_count = 3;
+ const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f;
+ const char* text_end_ellipsis = NULL;
+
+ float text_width = ImMax((pos_max.x - ellipsis_width) - pos_min.x, 1.0f);
+ float text_size_clipped_x = font->CalcTextSizeA(font_size, text_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
+ if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
+ {
+ // Always display at least 1 character if there's no room for character + ellipsis
+ text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
+ text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
+ }
+ while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
+ {
+ // Trim trailing space before ellipsis
+ text_end_ellipsis--;
+ text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
+ }
+ RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
+
+ const float ellipsis_x = pos_min.x + text_size_clipped_x + 1.0f;
+ if (ellipsis_x + ellipsis_width - 1.0f <= ellipsis_max_x)
+ RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_dot_count);
+ }
+ else
+ {
+ RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
+ }
+
+ if (g.LogEnabled)
+ LogRenderedText(&pos_min, text, text_end_full);
+}
+
// Render a rectangle shaped with optional rounding and borders
void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
{
@@ -2439,13 +2503,11 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
}
// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state
-void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale)
+void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)
{
- ImGuiContext& g = *GImGui;
-
- const float h = g.FontSize * 1.00f;
+ const float h = draw_list->_Data->FontSize * 1.00f;
float r = h * 0.40f * scale;
- ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale);
+ ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);
ImVec2 a, b, c;
switch (dir)
@@ -2469,15 +2531,12 @@ void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale)
IM_ASSERT(0);
break;
}
-
- g.CurrentWindow->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text));
+ draw_list->AddTriangleFilled(center + a, center + b, center + c, col);
}
-void ImGui::RenderBullet(ImVec2 pos)
+void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- window->DrawList->AddCircleFilled(pos, g.FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
+ draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
}
void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
@@ -2544,7 +2603,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
Flags = ImGuiWindowFlags_None;
Pos = ImVec2(0.0f, 0.0f);
Size = SizeFull = ImVec2(0.0f, 0.0f);
- SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
+ ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f);
WindowPadding = ImVec2(0.0f, 0.0f);
WindowRounding = 0.0f;
WindowBorderSize = 0.0f;
@@ -2618,6 +2677,14 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
return id;
}
+ImGuiID ImGuiWindow::GetID(int n)
+{
+ ImGuiID seed = IDStack.back();
+ ImGuiID id = ImHashData(&n, sizeof(n), seed);
+ ImGui::KeepAliveID(id);
+ return id;
+}
+
ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
{
ImGuiID seed = IDStack.back();
@@ -2630,6 +2697,12 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
return ImHashData(&ptr, sizeof(void*), seed);
}
+ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
+{
+ ImGuiID seed = IDStack.back();
+ return ImHashData(&n, sizeof(n), seed);
+}
+
// This is only used in rare/specific situations to manufacture an ID out of nowhere.
ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
{
@@ -2674,8 +2747,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
if (g.ActiveIdIsJustActivated)
{
g.ActiveIdTimer = 0.0f;
- g.ActiveIdHasBeenPressed = false;
- g.ActiveIdHasBeenEdited = false;
+ g.ActiveIdHasBeenPressedBefore = false;
+ g.ActiveIdHasBeenEditedBefore = false;
if (id != 0)
{
g.LastActiveId = id;
@@ -2687,6 +2760,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
g.ActiveIdBlockNavInputFlags = 0;
g.ActiveIdAllowOverlap = false;
g.ActiveIdWindow = window;
+ g.ActiveIdHasBeenEditedThisFrame = false;
if (id)
{
g.ActiveIdIsAlive = id;
@@ -2754,7 +2828,8 @@ void ImGui::MarkItemEdited(ImGuiID id)
IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
- g.ActiveIdHasBeenEdited = true;
+ g.ActiveIdHasBeenEditedThisFrame = true;
+ g.ActiveIdHasBeenEditedBefore = true;
g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
}
@@ -2787,10 +2862,11 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
return;
// Always align ourselves on pixel boundaries
- const float line_height = ImMax(window->DC.CurrentLineSize.y, size.y);
- const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
+ const float line_height = ImMax(window->DC.CurrLineSize.y, size.y);
+ const float text_base_offset = ImMax(window->DC.CurrLineTextBaseOffset, text_offset_y);
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
- window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
+ window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
+ window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
@@ -2799,7 +2875,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
window->DC.PrevLineSize.y = line_height;
window->DC.PrevLineTextBaseOffset = text_base_offset;
- window->DC.CurrentLineSize.y = window->DC.CurrentLineTextBaseOffset = 0.0f;
+ window->DC.CurrLineSize.y = window->DC.CurrLineTextBaseOffset = 0.0f;
// Horizontal layout mode
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
@@ -2823,9 +2899,13 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
- // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window.
- // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
- // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
+ // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
+ // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
+ // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
+ // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
+ // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
+ // 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 |= window->DC.NavLayerCurrentMask;
if (g.NavId == id || g.NavAnyRequest)
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
@@ -2836,6 +2916,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
window->DC.LastItemId = id;
window->DC.LastItemRect = bb;
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
+ g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (id != 0)
@@ -2983,7 +3064,7 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
ImGuiWindow* window = GImGui->CurrentWindow;
if (wrap_pos_x == 0.0f)
- wrap_pos_x = GetWorkRectMax().x;
+ wrap_pos_x = window->WorkRect.Max.x;
else if (wrap_pos_x > 0.0f)
wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
@@ -3023,7 +3104,7 @@ const char* ImGui::GetVersion()
return IMGUI_VERSION;
}
-// Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
+// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module
ImGuiContext* ImGui::GetCurrentContext()
{
@@ -3042,7 +3123,7 @@ void ImGui::SetCurrentContext(ImGuiContext* ctx)
// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
-// may see different structures thanwhat imgui.cpp sees, which is problematic.
+// may see different structures than what imgui.cpp sees, which is problematic.
// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
{
@@ -3316,7 +3397,7 @@ void ImGui::UpdateMouseWheel()
// Zoom / Scale window
// FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
- if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
+ if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling && !window->Collapsed)
{
const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
const float scale = new_font_scale / window->FontWindowScale;
@@ -3324,7 +3405,7 @@ void ImGui::UpdateMouseWheel()
if (!(window->Flags & ImGuiWindowFlags_ChildWindow))
{
const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
- window->Pos = ImFloor(window->Pos + offset);
+ SetWindowPos(window, window->Pos + offset, 0);
window->Size = ImFloor(window->Size * scale);
window->SizeFull = ImFloor(window->SizeFull * scale);
}
@@ -3402,13 +3483,13 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
g.HoveredWindow = g.HoveredRootWindow = NULL;
- // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app)
+ // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app)
if (g.WantCaptureMouseNextFrame != -1)
g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
else
g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
- // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app)
+ // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app)
if (g.WantCaptureKeyboardNextFrame != -1)
g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
else
@@ -3440,6 +3521,8 @@ void ImGui::NewFrame()
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!");
IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
+ IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
+
for (int n = 0; n < ImGuiKey_COUNT; n++)
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
@@ -3486,16 +3569,21 @@ void ImGui::NewFrame()
IM_ASSERT(g.Font->IsLoaded());
g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
+ g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
+ if (g.Style.AntiAliasedLines)
+ g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
+ if (g.Style.AntiAliasedFill)
+ g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
+ if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
+ g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
g.BackgroundDrawList.Clear();
g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);
g.BackgroundDrawList.PushClipRectFullScreen();
- g.BackgroundDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
g.ForegroundDrawList.Clear();
g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID);
g.ForegroundDrawList.PushClipRectFullScreen();
- g.ForegroundDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
// Mark rendering data as invalid to prevent user who may have a handle on it to use it.
g.DrawData.Clear();
@@ -3523,8 +3611,9 @@ void ImGui::NewFrame()
g.LastActiveIdTimer += g.IO.DeltaTime;
g.ActiveIdPreviousFrame = g.ActiveId;
g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
- g.ActiveIdPreviousFrameHasBeenEdited = g.ActiveIdHasBeenEdited;
+ g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
g.ActiveIdIsAlive = 0;
+ g.ActiveIdHasBeenEditedThisFrame = false;
g.ActiveIdPreviousFrameIsAlive = false;
g.ActiveIdIsJustActivated = false;
if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId)
@@ -3553,9 +3642,12 @@ void ImGui::NewFrame()
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;
+ // Find hovered window
+ // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
+ UpdateHoveredWindowAndCaptureFlags();
+
// Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
UpdateMouseMovingWindowNewFrame();
- UpdateHoveredWindowAndCaptureFlags();
// Background darkening/whitening
if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
@@ -3663,7 +3755,7 @@ void ImGui::Shutdown(ImGuiContext* context)
}
g.IO.Fonts = NULL;
- // Cleanup of other data are conditional on actually having initialized ImGui.
+ // Cleanup of other data are conditional on actually having initialized Dear ImGui.
if (!g.Initialized)
return;
@@ -3734,7 +3826,7 @@ static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, Im
{
int count = window->DC.ChildWindows.Size;
if (count > 1)
- ImQsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
+ ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
for (int i = 0; i < count; i++)
{
ImGuiWindow* child = window->DC.ChildWindows[i];
@@ -3758,19 +3850,28 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
return;
}
- // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly.
+ // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
+ // May trigger for you if you are using PrimXXX functions incorrectly.
IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
- IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
+ if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
+ IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
// Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
// If this assert triggers because you are drawing lots of stuff manually:
- // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents.
- // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes.
- // You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing:
- // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
- // Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API.
- // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
+ // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
+ // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents.
+ // - If you want large meshes with more than 64K vertices, you can either:
+ // (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
+ // Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't.
+ // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
+ // (B) Or handle 32-bits indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
+ // Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
+ // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
+ // Your own engine or render API may use different parameters or function calls to specify index sizes.
+ // 2 and 4 bytes indices are generally supported by most graphics API.
+ // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
+ // the 64K limit to split your draw commands in multiple draw lists.
if (sizeof(ImDrawIdx) == 2)
IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
@@ -4329,13 +4430,15 @@ bool ImGui::IsItemDeactivated()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
+ if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
+ return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
}
bool ImGui::IsItemDeactivatedAfterEdit()
{
ImGuiContext& g = *GImGui;
- return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEdited || (g.ActiveId == 0 && g.ActiveIdHasBeenEdited));
+ return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
}
bool ImGui::IsItemFocused()
@@ -4604,8 +4707,8 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
if (ImLengthSqr(settings->Size) > 0.00001f)
size = ImFloor(settings->Size);
}
- window->Size = window->SizeFull = window->SizeFullAtLastBegin = ImFloor(size);
- window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values
+ window->Size = window->SizeFull = ImFloor(size);
+ window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
{
@@ -4632,7 +4735,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
{
ImGuiContext& g = *GImGui;
- if (g.NextWindowData.SizeConstraintCond != 0)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
{
// Using -1,-1 on either X/Y axis to preserve the current size.
ImRect cr = g.NextWindowData.SizeConstraintRect;
@@ -4661,45 +4764,50 @@ static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
return new_size;
}
-static ImVec2 CalcSizeContents(ImGuiWindow* window)
+static ImVec2 CalcContentSize(ImGuiWindow* window)
{
if (window->Collapsed)
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
- return window->SizeContents;
+ return window->ContentSize;
if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
- return window->SizeContents;
+ return window->ContentSize;
ImVec2 sz;
- sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x));
- sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y));
- return sz + window->WindowPadding;
+ sz.x = (float)(int)((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
+ sz.y = (float)(int)((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
+ return sz;
}
static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
{
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
+ ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight());
+ ImVec2 size_pad = window->WindowPadding * 2.0f;
+ ImVec2 size_desired = size_contents + size_pad + size_decorations;
if (window->Flags & ImGuiWindowFlags_Tooltip)
{
// Tooltip always resize
- return size_contents;
+ return size_desired;
}
else
{
- // Maximum window size is determined by the display size
+ // Maximum window size is determined by the viewport size or monitor size
const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
ImVec2 size_min = style.WindowMinSize;
if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups)
size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
- ImVec2 size_auto_fit = ImClamp(size_contents, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
+ ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
// 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 = CalcSizeAfterConstraint(window, size_auto_fit);
- if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar))
+ 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);
+ if (will_have_scrollbar_x)
size_auto_fit.y += style.ScrollbarSize;
- if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar))
+ if (will_have_scrollbar_y)
size_auto_fit.x += style.ScrollbarSize;
return size_auto_fit;
}
@@ -4707,20 +4815,10 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window)
{
- ImVec2 size_contents = CalcSizeContents(window);
+ ImVec2 size_contents = CalcContentSize(window);
return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents));
}
-float ImGui::GetWindowScrollMaxX(ImGuiWindow* window)
-{
- return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x));
-}
-
-float ImGui::GetWindowScrollMaxY(ImGuiWindow* window)
-{
- return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y));
-}
-
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges)
{
ImGuiContext& g = *GImGui;
@@ -4728,7 +4826,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s
if (window->ScrollTarget.x < FLT_MAX)
{
float cr_x = window->ScrollTargetCenterRatio.x;
- scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
+ scroll.x = window->ScrollTarget.x - cr_x * window->InnerRect.GetWidth();
}
if (window->ScrollTarget.y < FLT_MAX)
{
@@ -4737,15 +4835,15 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s
float target_y = window->ScrollTarget.y;
if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y)
target_y = 0.0f;
- if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y)
- target_y = window->SizeContents.y;
- scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y);
+ if (snap_on_edges && cr_y >= 1.0f && target_y >= window->ContentSize.y + window->WindowPadding.y + g.Style.ItemSpacing.y)
+ target_y = window->ContentSize.y + window->WindowPadding.y * 2.0f;
+ scroll.y = target_y - cr_y * window->InnerRect.GetHeight();
}
scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
if (!window->Collapsed && !window->SkipItems)
{
- scroll.x = ImMin(scroll.x, ImGui::GetWindowScrollMaxX(window));
- scroll.y = ImMin(scroll.y, ImGui::GetWindowScrollMaxY(window));
+ scroll.x = ImMin(scroll.x, window->ScrollMax.x);
+ scroll.y = ImMin(scroll.y, window->ScrollMax.y);
}
return scroll;
}
@@ -4801,15 +4899,18 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_
}
// Handle resize for: Resize Grips, Borders, Gamepad
-static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
+// Return true when using auto-fit (double click on resize grip)
+static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
{
ImGuiContext& g = *GImGui;
ImGuiWindowFlags flags = window->Flags;
+
if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
- return;
+ return false;
if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
- return;
+ return false;
+ bool ret_auto_fit = false;
const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f);
@@ -4843,6 +4944,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
{
// Manual auto-fit when double-clicking
size_target = CalcSizeAfterConstraint(window, size_auto_fit);
+ ret_auto_fit = true;
ClearActiveID();
}
else if (held)
@@ -4917,6 +5019,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
window->Size = window->SizeFull;
+ return ret_auto_fit;
}
static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding)
@@ -4926,7 +5029,7 @@ static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, cons
window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping);
}
-static void ImGui::RenderOuterBorders(ImGuiWindow* window)
+static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
float rounding = window->WindowRounding;
@@ -4963,6 +5066,166 @@ static void ImGui::RenderOuterBorders(ImGuiWindow* window)
}
}
+void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiStyle& style = g.Style;
+ ImGuiWindowFlags flags = window->Flags;
+
+ // Draw window + handle manual resize
+ // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame.
+ const float window_rounding = window->WindowRounding;
+ const float window_border_size = window->WindowBorderSize;
+ if (window->Collapsed)
+ {
+ // Title bar only
+ float backup_border_size = style.FrameBorderSize;
+ g.Style.FrameBorderSize = window->WindowBorderSize;
+ ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
+ RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
+ g.Style.FrameBorderSize = backup_border_size;
+ }
+ else
+ {
+ // Window background
+ if (!(flags & ImGuiWindowFlags_NoBackground))
+ {
+ ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
+ float alpha = 1.0f;
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
+ alpha = g.NextWindowData.BgAlphaVal;
+ if (alpha != 1.0f)
+ bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
+ window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
+ }
+
+ // Title bar
+ if (!(flags & ImGuiWindowFlags_NoTitleBar))
+ {
+ ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
+ window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
+ }
+
+ // Menu bar
+ if (flags & ImGuiWindowFlags_MenuBar)
+ {
+ ImRect menu_bar_rect = window->MenuBarRect();
+ menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
+ window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
+ if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
+ window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
+ }
+
+ // Scrollbars
+ if (window->ScrollbarX)
+ Scrollbar(ImGuiAxis_X);
+ if (window->ScrollbarY)
+ Scrollbar(ImGuiAxis_Y);
+
+ // Render resize grips (after their input handling so we don't have a frame of latency)
+ if (!(flags & ImGuiWindowFlags_NoResize))
+ {
+ 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);
+ window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
+ window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
+ window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
+ window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
+ }
+ }
+
+ // Borders
+ RenderWindowOuterBorders(window);
+ }
+}
+
+// Render title text, collapse button, close button
+void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiStyle& style = g.Style;
+ ImGuiWindowFlags flags = window->Flags;
+
+ const bool has_close_button = (p_open != NULL);
+ const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse);
+
+ // 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;
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
+
+ // Layout buttons
+ // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
+ float pad_l = style.FramePadding.x;
+ float pad_r = style.FramePadding.x;
+ float button_sz = g.FontSize;
+ ImVec2 close_button_pos;
+ ImVec2 collapse_button_pos;
+ if (has_close_button)
+ {
+ pad_r += button_sz;
+ close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
+ }
+ if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
+ {
+ pad_r += button_sz;
+ collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
+ }
+ if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
+ {
+ collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
+ pad_l += button_sz;
+ }
+
+ // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
+ if (has_collapse_button)
+ if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
+ window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
+
+ // Close button
+ if (has_close_button)
+ if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
+ *p_open = false;
+
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
+ window->DC.ItemFlags = 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..
+ const char* UNSAVED_DOCUMENT_MARKER = "*";
+ const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
+ const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
+
+ // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
+ // while uncentered title text will still reach edges correct.
+ if (pad_l > style.FramePadding.x)
+ pad_l += g.Style.ItemInnerSpacing.x;
+ if (pad_r > style.FramePadding.x)
+ pad_r += g.Style.ItemInnerSpacing.x;
+ if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
+ {
+ float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
+ float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
+ pad_l = ImMax(pad_l, pad_extend * centerness);
+ pad_r = ImMax(pad_r, pad_extend * centerness);
+ }
+
+ ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);
+ ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y);
+ //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
+ RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
+ if (flags & ImGuiWindowFlags_UnsavedDocument)
+ {
+ ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
+ ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f));
+ RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
+ }
+}
+
void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
{
window->ParentWindow = parent_window;
@@ -4978,7 +5241,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
}
}
-// Push a new ImGui window to add widgets to.
+// Push a new Dear ImGui window to add widgets to.
// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
// - Begin/End can be called multiple times during the frame with the same window name to append content.
// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
@@ -4998,7 +5261,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const bool window_just_created = (window == NULL);
if (window_just_created)
{
- ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
+ ImVec2 size_on_first_use = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
window = CreateNewWindow(name, size_on_first_use, flags);
}
@@ -5062,7 +5325,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Process SetNextWindow***() calls
bool window_pos_set_by_api = false;
bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
- if (g.NextWindowData.PosCond)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
{
window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
@@ -5078,26 +5341,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
}
}
- if (g.NextWindowData.SizeCond)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
{
window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
}
- if (g.NextWindowData.ContentSizeCond)
- {
- // Adjust passed "client size" to become a "window size"
- window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal;
- if (window->SizeContentsExplicit.y != 0.0f)
- window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight();
- }
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
+ window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;
else if (first_begin_of_the_frame)
- {
- window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
- }
- if (g.NextWindowData.CollapsedCond)
+ window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
- if (g.NextWindowData.FocusCond)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
FocusWindow(window);
if (window->Appearing)
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
@@ -5129,7 +5385,7 @@ 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)
- window->SizeContents = CalcSizeContents(window);
+ window->ContentSize = CalcContentSize(window);
if (window->HiddenFramesCanSkipItems > 0)
window->HiddenFramesCanSkipItems--;
if (window->HiddenFramesCannotSkipItems > 0)
@@ -5140,7 +5396,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->HiddenFramesCannotSkipItems = 1;
// Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
- // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
+ // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
{
window->HiddenFramesCannotSkipItems = 1;
@@ -5150,13 +5406,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->Size.x = window->SizeFull.x = 0.f;
if (!window_size_y_set_by_api)
window->Size.y = window->SizeFull.y = 0.f;
- window->SizeContents = ImVec2(0.f, 0.f);
+ window->ContentSize = ImVec2(0.f, 0.f);
}
}
+ // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)
SetCurrentWindow(window);
- // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies)
+ // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
+
if (flags & ImGuiWindowFlags_ChildWindow)
window->WindowBorderSize = style.ChildBorderSize;
else
@@ -5191,24 +5449,37 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// SIZE
// Calculate auto-fit size, handle automatic resize
- const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents);
- ImVec2 size_full_modified(FLT_MAX, FLT_MAX);
+ const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->ContentSize);
+ bool use_current_size_for_scrollbar_x = window_just_created;
+ bool use_current_size_for_scrollbar_y = window_just_created;
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
{
// Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
if (!window_size_x_set_by_api)
- window->SizeFull.x = size_full_modified.x = size_auto_fit.x;
+ {
+ window->SizeFull.x = size_auto_fit.x;
+ use_current_size_for_scrollbar_x = true;
+ }
if (!window_size_y_set_by_api)
- window->SizeFull.y = size_full_modified.y = size_auto_fit.y;
+ {
+ window->SizeFull.y = size_auto_fit.y;
+ use_current_size_for_scrollbar_y = true;
+ }
}
else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
{
// Auto-fit may only grow window during the first few frames
// We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
- window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
+ {
+ window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
+ use_current_size_for_scrollbar_x = true;
+ }
if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
- window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
+ {
+ window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
+ use_current_size_for_scrollbar_y = true;
+ }
if (!window->Collapsed)
MarkIniSettingsDirty(window);
}
@@ -5217,20 +5488,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull);
window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
- // SCROLLBAR STATUS
-
- // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size).
- if (!window->Collapsed)
- {
- // When reading the current size we need to read it after size constraints have been applied
- float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x;
- float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y;
- window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
- window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
- if (window->ScrollbarX && !window->ScrollbarY)
- window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
- window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
- }
+ // Decoration size
+ const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
// POSITION
@@ -5262,7 +5521,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
window->Pos = FindBestWindowPosForPopup(window);
- // Clamp position so it stays visible
+ // Clamp position/size so window stays visible within its viewport or monitor
+
// Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
ImRect viewport_rect(GetViewportRect());
if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
@@ -5278,10 +5538,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
- // Apply scrolling
- window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true);
- window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
-
// Apply window focus (new and reactivated windows are moved to front)
bool want_focus = false;
if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
@@ -5296,27 +5552,96 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
int border_held = -1;
ImU32 resize_grip_col[4] = { 0 };
const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4
- const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
+ const float resize_grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
if (!window->Collapsed)
- UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]);
+ if (UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]))
+ use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
window->ResizeBorderHeld = (signed char)border_held;
+ // SCROLLBAR VISIBILITY
+
+ // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
+ if (!window->Collapsed)
+ {
+ // When reading the current size we need to read it after size constraints have been applied.
+ // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again.
+ ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height);
+ ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes;
+ ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
+ float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
+ float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
+ //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
+ window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
+ window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
+ if (window->ScrollbarX && !window->ScrollbarY)
+ window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
+ window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
+ }
+
+ // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
+ // Update various regions. Variables they depends on should be set above in this function.
+ // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
+
+ // Outer rectangle
+ // Not affected by window border size. Used by:
+ // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
+ // - Begin() initial clipping rect for drawing window background and borders.
+ // - Begin() clipping whole child
+ const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
+ const ImRect outer_rect = window->Rect();
+ const ImRect title_bar_rect = window->TitleBarRect();
+ window->OuterRectClipped = outer_rect;
+ window->OuterRectClipped.ClipWith(host_rect);
+
+ // Inner rectangle
+ // Not affected by window border size. Used by:
+ // - InnerClipRect
+ // - NavScrollToBringItemIntoView()
+ // - NavUpdatePageUpPageDown()
+ // - Scrollbar()
+ window->InnerRect.Min.x = window->Pos.x;
+ window->InnerRect.Min.y = window->Pos.y + decoration_up_height;
+ window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x;
+ window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y;
+
+ // Inner clipping rectangle.
+ // Will extend a little bit outside the normal work region.
+ // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
+ // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
+ // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
+ // Affected by window/frame border size. Used by:
+ // - Begin() initial clip rect
+ float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
+ window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
+ window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
+ window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.y * 0.5f), window->WindowBorderSize));
+ window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
+ window->InnerClipRect.ClipWithFull(host_rect);
+
// Default item width. Make it proportional to window size if window manually resizes
if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
else
window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
+ // SCROLLING
+
+ // Lock down maximum scrolling
+ // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
+ // for right/bottom aligned items without creating a scrollbar.
+ window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
+ window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
+
+ // Apply scrolling
+ window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true);
+ window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
+
// DRAWING
// Setup draw list and outer clipping rectangle
window->DrawList->Clear();
- window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
- if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
- PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
- else
- PushClipRect(viewport_rect.Min, viewport_rect.Max, true);
+ PushClipRect(host_rect.Min, host_rect.Max, false);
// Draw modal window background (darkens what is behind them, all viewports)
const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
@@ -5336,77 +5661,24 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
}
- // Draw window + handle manual resize
- // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame.
- const float window_rounding = window->WindowRounding;
- const float window_border_size = window->WindowBorderSize;
+ // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call.
+ // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
+ // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child.
+ // We also disabled this when we have dimming overlay behind this specific one child.
+ // FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected.
+ bool render_decorations_in_parent = false;
+ if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
+ if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
+ render_decorations_in_parent = true;
+ if (render_decorations_in_parent)
+ window->DrawList = parent_window->DrawList;
+
const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
- const ImRect title_bar_rect = window->TitleBarRect();
- if (window->Collapsed)
- {
- // Title bar only
- float backup_border_size = style.FrameBorderSize;
- g.Style.FrameBorderSize = window->WindowBorderSize;
- ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
- RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
- g.Style.FrameBorderSize = backup_border_size;
- }
- else
- {
- // Window background
- if (!(flags & ImGuiWindowFlags_NoBackground))
- {
- ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
- float alpha = 1.0f;
- if (g.NextWindowData.BgAlphaCond != 0)
- alpha = g.NextWindowData.BgAlphaVal;
- if (alpha != 1.0f)
- bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
- window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
- }
- g.NextWindowData.BgAlphaCond = 0;
-
- // Title bar
- if (!(flags & ImGuiWindowFlags_NoTitleBar))
- {
- ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
- window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
- }
+ RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
- // Menu bar
- if (flags & ImGuiWindowFlags_MenuBar)
- {
- ImRect menu_bar_rect = window->MenuBarRect();
- menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
- window->DrawList->AddRectFilled(menu_bar_rect.Min+ImVec2(window_border_size,0), menu_bar_rect.Max-ImVec2(window_border_size,0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
- if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
- window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
- }
-
- // Scrollbars
- if (window->ScrollbarX)
- Scrollbar(ImGuiAxis_X);
- if (window->ScrollbarY)
- Scrollbar(ImGuiAxis_Y);
-
- // Render resize grips (after their input handling so we don't have a frame of latency)
- if (!(flags & ImGuiWindowFlags_NoResize))
- {
- 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);
- window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size)));
- window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size)));
- window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
- window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
- }
- }
-
- // Borders
- RenderOuterBorders(window);
- }
+ if (render_decorations_in_parent)
+ window->DrawList = &window->DrawListInst;
// Draw navigation selection/windowing rectangle border
if (g.NavWindowingTargetAnim == window)
@@ -5422,48 +5694,44 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
}
- // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars.
- window->SizeFullAtLastBegin = window->SizeFull;
-
- // Update various regions. Variables they depends on are set above in this function.
- // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
- // NB: WindowBorderSize is included in WindowPadding _and_ ScrollbarSizes so we need to cancel one out.
+ // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
+
+ // Work rectangle.
+ // Affected by window padding and border size. Used by:
+ // - Columns() for right-most edge
+ // - TreeNode(), CollapsingHeader() for right-most edge
+ // - BeginTabBar() for right-most edge
+ const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
+ const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
+ const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
+ const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
+ window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
+ window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
+ window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
+ window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
+
+ // [LEGACY] Contents Region
+ // FIXME-OBSOLETE: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
+ // Used by:
+ // - Mouse wheel scrolling + many other things
window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
- window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
- window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x + ImMin(window->ScrollbarSizes.x, window->WindowBorderSize)));
- window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y + ImMin(window->ScrollbarSizes.y, window->WindowBorderSize)));
-
- // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
- window->OuterRectClipped = window->Rect();
- window->OuterRectClipped.ClipWith(window->ClipRect);
-
- // Inner rectangle
- // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
- // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
- window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize;
- window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
- window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize);
- window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - ImMax(window->ScrollbarSizes.y, window->WindowBorderSize);
+ window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
+ window->ContentsRegionRect.Max.x = window->ContentsRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
+ window->ContentsRegionRect.Max.y = window->ContentsRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
- // Inner clipping rectangle
- // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
- window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize)));
- window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y);
- window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize)));
- window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y);
// Setup drawing context
// (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
window->DC.GroupOffset.x = 0.0f;
window->DC.ColumnsOffset.x = 0.0f;
- window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
+ window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
window->DC.CursorPos = window->DC.CursorStartPos;
window->DC.CursorPosPrevLine = window->DC.CursorPos;
window->DC.CursorMaxPos = window->DC.CursorStartPos;
- window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
- window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
+ window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.NavHideHighlightOneFrame = false;
- window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f);
+ window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
window->DC.NavLayerActiveMaskNext = 0x00;
window->DC.MenuBarAppending = false;
@@ -5504,52 +5772,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Title bar
if (!(flags & ImGuiWindowFlags_NoTitleBar))
- {
- // Close & collapse button are on layer 1 (same as menus) and don't default focus
- const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
- window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
- window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
- window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
-
- // Collapse button
- if (!(flags & ImGuiWindowFlags_NoCollapse))
- if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos))
- window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function
-
- // Close button
- if (p_open != NULL)
- {
- const float rad = g.FontSize * 0.5f;
- if (CloseButton(window->GetID("#CLOSE"), ImVec2(window->Pos.x + window->Size.x - style.FramePadding.x - rad, window->Pos.y + style.FramePadding.y + rad), rad + 1))
- *p_open = false;
- }
-
- window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
- window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
- window->DC.ItemFlags = 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 too much code..
- const char* UNSAVED_DOCUMENT_MARKER = "*";
- float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
- ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
- ImRect text_r = title_bar_rect;
- float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
- float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
- if (style.WindowTitleAlign.x > 0.0f)
- pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x);
- text_r.Min.x += pad_left;
- text_r.Max.x -= pad_right;
- ImRect clip_rect = text_r;
- clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton()
- RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect);
- if (flags & ImGuiWindowFlags_UnsavedDocument)
- {
- ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
- ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f));
- RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect);
- }
- }
+ RenderWindowTitleBarContents(window, title_bar_rect, name, p_open);
// Pressing CTRL+C while holding on a window copy its content to the clipboard
// This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
@@ -5583,7 +5806,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->WriteAccessed = false;
window->BeginCount++;
- g.NextWindowData.Clear();
+ g.NextWindowData.ClearFlags();
if (flags & ImGuiWindowFlags_ChildWindow)
{
@@ -5771,20 +5994,24 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
void ImGui::SetNextItemWidth(float item_width)
{
- ImGuiWindow* window = GetCurrentWindow();
- window->DC.NextItemWidth = item_width;
+ ImGuiContext& g = *GImGui;
+ g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
+ g.NextItemData.Width = item_width;
}
void ImGui::PushItemWidth(float item_width)
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
+ g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
}
void ImGui::PushMultiItemsWidths(int components, float w_full)
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
const ImGuiStyle& style = GImGui->Style;
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
@@ -5792,6 +6019,7 @@ void ImGui::PushMultiItemsWidths(int components, float w_full)
for (int i = 0; i < components-1; i++)
window->DC.ItemWidthStack.push_back(w_item_one);
window->DC.ItemWidth = window->DC.ItemWidthStack.back();
+ g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
}
void ImGui::PopItemWidth()
@@ -5801,52 +6029,37 @@ void ImGui::PopItemWidth()
window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
}
-// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(),
-// Then consume the
-float ImGui::GetNextItemWidth()
+// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
+// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
+float ImGui::CalcItemWidth()
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
float w;
- if (window->DC.NextItemWidth != FLT_MAX)
- {
- w = window->DC.NextItemWidth;
- window->DC.NextItemWidth = FLT_MAX;
- }
+ if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
+ w = g.NextItemData.Width;
else
- {
w = window->DC.ItemWidth;
- }
if (w < 0.0f)
{
- float region_max_x = GetWorkRectMax().x;
+ float region_max_x = GetContentRegionMaxAbs().x;
w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
}
w = (float)(int)w;
return w;
}
-// Calculate item width *without* popping/consuming NextItemWidth if it was set.
-// (rarely used, which is why we avoid calling this from GetNextItemWidth() and instead do a backup/restore here)
-float ImGui::CalcItemWidth()
-{
- ImGuiWindow* window = GImGui->CurrentWindow;
- float backup_next_item_width = window->DC.NextItemWidth;
- float w = GetNextItemWidth();
- window->DC.NextItemWidth = backup_next_item_width;
- return w;
-}
-
-// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == GetNextItemWidth().
+// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
// Note that only CalcItemWidth() is publicly exposed.
-// The 4.0f here may be changed to match GetNextItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
+// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
{
ImGuiWindow* window = GImGui->CurrentWindow;
ImVec2 region_max;
if (size.x < 0.0f || size.y < 0.0f)
- region_max = GetWorkRectMax();
+ region_max = GetContentRegionMaxAbs();
if (size.x == 0.0f)
size.x = default_w;
@@ -6227,16 +6440,12 @@ ImVec2 ImGui::GetWindowPos()
void ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
{
- window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
window->Scroll.x = new_scroll_x;
- window->DC.CursorMaxPos.x -= window->Scroll.x;
}
void ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
{
- window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
window->Scroll.y = new_scroll_y;
- window->DC.CursorMaxPos.y -= window->Scroll.y;
}
void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
@@ -6252,8 +6461,10 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
// Set
const ImVec2 old_pos = window->Pos;
window->Pos = ImFloor(pos);
- window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
- window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
+ ImVec2 offset = window->Pos - old_pos;
+ window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
+ window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
+ window->DC.CursorStartPos += offset;
}
void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
@@ -6373,6 +6584,7 @@ void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pi
{
ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
g.NextWindowData.PosVal = pos;
g.NextWindowData.PosPivotVal = pivot;
g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
@@ -6382,6 +6594,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
g.NextWindowData.SizeVal = size;
g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
}
@@ -6389,23 +6602,26 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
{
ImGuiContext& g = *GImGui;
- g.NextWindowData.SizeConstraintCond = ImGuiCond_Always;
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
g.NextWindowData.SizeCallback = custom_callback;
g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
}
+// Content size = inner scrollable rectangle, padded with WindowPadding.
+// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
void ImGui::SetNextWindowContentSize(const ImVec2& size)
{
ImGuiContext& g = *GImGui;
- g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value.
- g.NextWindowData.ContentSizeCond = ImGuiCond_Always;
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
+ g.NextWindowData.ContentSizeVal = size;
}
void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
g.NextWindowData.CollapsedVal = collapsed;
g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
}
@@ -6413,14 +6629,14 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
void ImGui::SetNextWindowFocus()
{
ImGuiContext& g = *GImGui;
- g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
}
void ImGui::SetNextWindowBgAlpha(float alpha)
{
ImGuiContext& g = *GImGui;
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
g.NextWindowData.BgAlphaVal = alpha;
- g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
}
// FIXME: This is in window space (not screen space!). We should try to obsolete all those functions.
@@ -6434,7 +6650,7 @@ ImVec2 ImGui::GetContentRegionMax()
}
// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
-ImVec2 ImGui::GetWorkRectMax()
+ImVec2 ImGui::GetContentRegionMaxAbs()
{
ImGuiWindow* window = GImGui->CurrentWindow;
ImVec2 mx = window->ContentsRegionRect.Max;
@@ -6446,7 +6662,7 @@ ImVec2 ImGui::GetWorkRectMax()
ImVec2 ImGui::GetContentRegionAvail()
{
ImGuiWindow* window = GImGui->CurrentWindow;
- return GetWorkRectMax() - window->DC.CursorPos;
+ return GetContentRegionMaxAbs() - window->DC.CursorPos;
}
// In window space (not screen space!)
@@ -6583,22 +6799,26 @@ void ImGui::SetCursorScreenPos(const ImVec2& pos)
float ImGui::GetScrollX()
{
- return GImGui->CurrentWindow->Scroll.x;
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->Scroll.x;
}
float ImGui::GetScrollY()
{
- return GImGui->CurrentWindow->Scroll.y;
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->Scroll.y;
}
float ImGui::GetScrollMaxX()
{
- return GetWindowScrollMaxX(GImGui->CurrentWindow);
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->ScrollMax.x;
}
float ImGui::GetScrollMaxY()
{
- return GetWindowScrollMaxY(GImGui->CurrentWindow);
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->ScrollMax.y;
}
void ImGui::SetScrollX(float scroll_x)
@@ -6611,7 +6831,7 @@ void ImGui::SetScrollX(float scroll_x)
void ImGui::SetScrollY(float scroll_y)
{
ImGuiWindow* window = GetCurrentWindow();
- window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
+ window->ScrollTarget.y = scroll_y;
window->ScrollTargetCenterRatio.y = 0.0f;
}
@@ -6698,9 +6918,8 @@ void ImGui::PushID(const void* ptr_id)
void ImGui::PushID(int int_id)
{
- const void* ptr_id = (void*)(intptr_t)int_id;
ImGuiWindow* window = GImGui->CurrentWindow;
- window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id));
+ window->IDStack.push_back(window->GetIDNoKeepAlive(int_id));
}
// Push a given id value ignoring the ID stack as a seed.
@@ -6758,16 +6977,16 @@ void ImGui::BeginGroup()
group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
group_data.BackupIndent = window->DC.Indent;
group_data.BackupGroupOffset = window->DC.GroupOffset;
- group_data.BackupCurrentLineSize = window->DC.CurrentLineSize;
- group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset;
+ group_data.BackupCurrLineSize = window->DC.CurrLineSize;
+ group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
- group_data.AdvanceCursor = true;
+ group_data.EmitItem = true;
window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
window->DC.Indent = window->DC.GroupOffset;
window->DC.CursorMaxPos = window->DC.CursorPos;
- window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
if (g.LogEnabled)
g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
}
@@ -6780,36 +6999,49 @@ void ImGui::EndGroup()
ImGuiGroupData& group_data = window->DC.GroupStack.back();
- ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
- group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
+ ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
window->DC.CursorPos = group_data.BackupCursorPos;
window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
window->DC.Indent = group_data.BackupIndent;
window->DC.GroupOffset = group_data.BackupGroupOffset;
- window->DC.CurrentLineSize = group_data.BackupCurrentLineSize;
- window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
+ window->DC.CurrLineSize = group_data.BackupCurrLineSize;
+ window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
if (g.LogEnabled)
g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
- if (group_data.AdvanceCursor)
+ if (!group_data.EmitItem)
{
- window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
- ItemSize(group_bb.GetSize(), 0.0f);
- ItemAdd(group_bb, 0);
+ window->DC.GroupStack.pop_back();
+ return;
}
+ window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
+ ItemSize(group_bb.GetSize(), 0.0f);
+ ItemAdd(group_bb, 0);
+
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
// It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
- // (and if you grep for LastItemId you'll notice it is only used in that context.
- if ((group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow)
+ // Also if you grep for LastItemId you'll notice it is only used in that context.
+ // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
+ const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
+ const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive;
+ if (group_contains_curr_active_id)
window->DC.LastItemId = g.ActiveId;
- else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow)
+ else if (group_contains_prev_active_id)
window->DC.LastItemId = g.ActiveIdPreviousFrame;
window->DC.LastItemRect = group_bb;
- window->DC.GroupStack.pop_back();
+ // Forward Edited flag
+ if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
+
+ // Forward Deactivated flag
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
+ if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
+ window->DC.GroupStack.pop_back();
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
}
@@ -6837,8 +7069,8 @@ void ImGui::SameLine(float offset_from_start_x, float spacing_w)
window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
}
- window->DC.CurrentLineSize = window->DC.PrevLineSize;
- window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
+ window->DC.CurrLineSize = window->DC.PrevLineSize;
+ window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
}
void ImGui::Indent(float indent_w)
@@ -7115,7 +7347,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
ImGuiContext& g = *GImGui;
if (!IsPopupOpen(id))
{
- g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
+ g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
}
@@ -7137,7 +7369,7 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
{
- g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
+ g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
}
flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
@@ -7145,7 +7377,7 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
}
// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
-// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
+// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
@@ -7153,13 +7385,13 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
const ImGuiID id = window->GetID(name);
if (!IsPopupOpen(id))
{
- g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
+ g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
}
// Center modal windows by default
// FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
- if (g.NextWindowData.PosCond == 0)
+ if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings;
@@ -7192,6 +7424,8 @@ void ImGui::EndPopup()
bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
{
ImGuiWindow* window = GImGui->CurrentWindow;
+ if (window->SkipItems)
+ return false;
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
@@ -7601,7 +7835,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov
ImGuiDir clip_dir = g.NavMoveDir;
if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
{
- bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x) - window->Scroll.x;
+ bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x;
if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
}
@@ -7613,7 +7847,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov
}
if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
{
- bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y) - window->Scroll.y;
+ bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y;
if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
}
@@ -7749,7 +7983,7 @@ ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInput
// NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated.
static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect)
{
- ImRect window_rect(window->InnerMainRect.Min - ImVec2(1, 1), window->InnerMainRect.Max + ImVec2(1, 1));
+ ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
//GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
if (window_rect.Contains(item_rect))
return;
@@ -7817,10 +8051,10 @@ static void ImGui::NavUpdate()
g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
// Process navigation init request (select first/default focus)
- if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
+ // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
+ if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow)
{
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
- IM_ASSERT(g.NavWindow);
if (g.NavInitRequestFromMove)
SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
else
@@ -8023,7 +8257,7 @@ static void ImGui::NavUpdate()
if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
{
ImGuiWindow* window = g.NavWindow;
- ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1));
+ ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1,1), window->InnerRect.Max - window->Pos + ImVec2(1,1));
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
{
float pad = window->CalcFontSize() * 0.5f;
@@ -8124,14 +8358,14 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
{
// Fallback manual-scroll when window has no navigable item
if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
- SetWindowScrollY(window, window->Scroll.y - window->InnerMainRect.GetHeight());
+ SetWindowScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
- SetWindowScrollY(window, window->Scroll.y + window->InnerMainRect.GetHeight());
+ SetWindowScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
}
else
{
const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
- const float page_offset_y = ImMax(0.0f, window->InnerMainRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
+ const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
float nav_scoring_rect_offset_y = 0.0f;
if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
{
@@ -8282,7 +8516,7 @@ static void ImGui::NavUpdateWindowing()
{
const float NAV_MOVE_SPEED = 800.0f;
const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well
- g.NavWindowingTarget->RootWindow->Pos += move_delta * move_speed;
+ SetWindowPos(g.NavWindowingTarget->RootWindow, g.NavWindowingTarget->RootWindow->Pos + move_delta * move_speed, ImGuiCond_Always);
g.NavDisableMouseHover = true;
MarkIniSettingsDirty(g.NavWindowingTarget);
}
@@ -8398,24 +8632,25 @@ void ImGui::NextColumn()
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
if (++columns->Current < columns->Count)
{
- // New column (columns 1+ cancels out IndentX)
+ // Columns 1+ cancel out IndentX
+ // FIXME-COLUMNS: Unnecessary, could be locked?
window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x;
- window->DrawList->ChannelsSetCurrent(columns->Current);
+ window->DrawList->ChannelsSetCurrent(columns->Current + 1);
}
else
{
// New row/line
window->DC.ColumnsOffset.x = 0.0f;
- window->DrawList->ChannelsSetCurrent(0);
+ window->DrawList->ChannelsSetCurrent(1);
columns->Current = 0;
columns->LineMinY = columns->LineMaxY;
}
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = columns->LineMinY;
- window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f);
- window->DC.CurrentLineTextBaseOffset = 0.0f;
+ window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.CurrLineTextBaseOffset = 0.0f;
- PushColumnClipRect();
+ PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite?
PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup
}
@@ -8433,12 +8668,12 @@ int ImGui::GetColumnsCount()
static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm)
{
- return offset_norm * (columns->MaxX - columns->MinX);
+ return offset_norm * (columns->OffMaxX - columns->OffMinX);
}
static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset)
{
- return offset / (columns->MaxX - columns->MinX);
+ return offset / (columns->OffMaxX - columns->OffMinX);
}
static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;
@@ -8471,7 +8706,7 @@ float ImGui::GetColumnOffset(int column_index)
IM_ASSERT(column_index < columns->Columns.Size);
const float t = columns->Columns[column_index].OffsetNorm;
- const float x_offset = ImLerp(columns->MinX, columns->MaxX, t);
+ const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);
return x_offset;
}
@@ -8514,8 +8749,8 @@ void ImGui::SetColumnOffset(int column_index, float offset)
const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
- offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
- columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX);
+ offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
+ columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX);
if (preserve_width)
SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
@@ -8543,6 +8778,26 @@ void ImGui::PushColumnClipRect(int column_index)
PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false);
}
+// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns)
+void ImGui::PushColumnsBackground()
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ window->DrawList->ChannelsSetCurrent(0);
+ int cmd_size = window->DrawList->CmdBuffer.Size;
+ PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false);
+ IM_UNUSED(cmd_size);
+ IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd
+}
+
+void ImGui::PopColumnsBackground()
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ window->DrawList->ChannelsSetCurrent(columns->Current + 1);
+ PopClipRect();
+}
+
ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id)
{
// We have few columns per window so for now we don't need bother much with turning this into a faster lookup.
@@ -8577,9 +8832,8 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
IM_ASSERT(columns_count >= 1);
IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported
- ImGuiID id = GetColumnsID(str_id, columns_count);
-
// Acquire storage for the columns set
+ ImGuiID id = GetColumnsID(str_id, columns_count);
ImGuiColumns* columns = FindOrCreateColumns(window, id);
IM_ASSERT(columns->ID == id);
columns->Current = 0;
@@ -8588,11 +8842,11 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
window->DC.CurrentColumns = columns;
// Set state for first column
- const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x);
- columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range
- columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f);
- columns->BackupCursorPosY = window->DC.CursorPos.y;
- columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x;
+ columns->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x;
+ columns->OffMaxX = ImMax(window->WorkRect.Max.x - window->Pos.x, columns->OffMinX + 1.0f);
+ columns->HostCursorPosY = window->DC.CursorPos.y;
+ columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x;
+ columns->HostClipRect = window->ClipRect;
columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
window->DC.ColumnsOffset.x = 0.0f;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
@@ -8601,7 +8855,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
columns->Columns.resize(0);
- // Initialize defaults
+ // Initialize default widths
columns->IsFirstFrame = (columns->Columns.Size == 0);
if (columns->Columns.Size == 0)
{
@@ -8626,8 +8880,9 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
if (columns->Count > 1)
{
- window->DrawList->ChannelsSplit(columns->Count);
- PushColumnClipRect();
+ window->DrawList->ChannelsSplit(1 + columns->Count);
+ window->DrawList->ChannelsSetCurrent(1);
+ PushColumnClipRect(0);
}
PushItemWidth(GetColumnWidth() * 0.65f);
}
@@ -8646,17 +8901,19 @@ void ImGui::EndColumns()
window->DrawList->ChannelsMerge();
}
+ const ImGuiColumnsFlags flags = columns->Flags;
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
window->DC.CursorPos.y = columns->LineMaxY;
- if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize))
- window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent
+ if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize))
+ window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent
// Draw columns borders and handle resize
+ // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy
bool is_being_resized = false;
- if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
+ if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
{
// We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.
- const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y);
+ const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y);
const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y);
int dragging_column = -1;
for (int n = 1; n < columns->Count; n++)
@@ -8671,7 +8928,7 @@ void ImGui::EndColumns()
continue;
bool hovered = false, held = false;
- if (!(columns->Flags & ImGuiColumnsFlags_NoResize))
+ if (!(flags & ImGuiColumnsFlags_NoResize))
{
ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
if (hovered || held)
@@ -8723,6 +8980,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
BeginColumns(id, columns_count, flags);
}
+
//-----------------------------------------------------------------------------
// [SECTION] DRAG AND DROP
//-----------------------------------------------------------------------------
@@ -9464,15 +9722,17 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
#else
#include <windows.h>
#endif
+#elif defined(__APPLE__)
+#include <TargetConditionals.h>
#endif
-// Win32 API clipboard implementation
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
#ifdef _MSC_VER
#pragma comment(lib, "user32")
#endif
+// Win32 clipboard implementation
static const char* GetClipboardTextFn_DefaultImpl(void*)
{
static ImVector<char> buf_local;
@@ -9516,16 +9776,66 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
::CloseClipboard();
}
+#elif defined(__APPLE__) && TARGET_OS_OSX && !defined(IMGUI_DISABLE_OSX_FUNCTIONS)
+
+#include <Carbon/Carbon.h> // Use old API to avoid need for separate .mm file
+static PasteboardRef main_clipboard = 0;
+
+// OSX clipboard implementation
+static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
+{
+ if (!main_clipboard)
+ PasteboardCreate(kPasteboardClipboard, &main_clipboard);
+ PasteboardClear(main_clipboard);
+ CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
+ if (cf_data)
+ {
+ PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
+ CFRelease(cf_data);
+ }
+}
+
+static const char* GetClipboardTextFn_DefaultImpl(void*)
+{
+ if (!main_clipboard)
+ PasteboardCreate(kPasteboardClipboard, &main_clipboard);
+ PasteboardSynchronize(main_clipboard);
+
+ ItemCount item_count = 0;
+ PasteboardGetItemCount(main_clipboard, &item_count);
+ for (int i = 0; i < item_count; i++)
+ {
+ PasteboardItemID item_id = 0;
+ PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
+ CFArrayRef flavor_type_array = 0;
+ PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
+ for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
+ {
+ CFDataRef cf_data;
+ if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
+ {
+ static ImVector<char> clipboard_text;
+ int length = (int)CFDataGetLength(cf_data);
+ clipboard_text.resize(length + 1);
+ CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)clipboard_text.Data);
+ clipboard_text[length] = 0;
+ CFRelease(cf_data);
+ return clipboard_text.Data;
+ }
+ }
+ }
+ return NULL;
+}
+
#else
-// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
+// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
static const char* GetClipboardTextFn_DefaultImpl(void*)
{
ImGuiContext& g = *GImGui;
return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin();
}
-// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
{
ImGuiContext& g = *GImGui;
@@ -9539,7 +9849,7 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
#endif
// Win32 API IME support (for Asian languages, etc.)
-#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
+#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
#include <imm.h>
#ifdef _MSC_VER
@@ -9573,16 +9883,16 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
void ImGui::ShowMetricsWindow(bool* p_open)
{
- if (!ImGui::Begin("ImGui Metrics", p_open))
+ if (!ImGui::Begin("Dear ImGui Metrics", p_open))
{
ImGui::End();
return;
}
- enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerMainRect, RT_InnerClipRect, RT_ContentsRegionRect, RT_ContentsFullRect };
+ enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect, RT_Count };
static bool show_windows_begin_order = false;
static bool show_windows_rects = false;
- static int show_windows_rect_type = RT_ContentsRegionRect;
+ static int show_windows_rect_type = RT_WorkRect;
static bool show_drawcmd_clip_rects = true;
ImGuiIO& io = ImGui::GetIO();
@@ -9595,6 +9905,19 @@ void ImGui::ShowMetricsWindow(bool* p_open)
struct Funcs
{
+ static ImRect GetRect(ImGuiWindow* window, int rect_type)
+ {
+ if (rect_type == RT_OuterRect) { return window->Rect(); }
+ else if (rect_type == RT_OuterRectClipped) { return window->OuterRectClipped; }
+ else if (rect_type == RT_InnerRect) { return window->InnerRect; }
+ else if (rect_type == RT_InnerClipRect) { return window->InnerClipRect; }
+ else if (rect_type == RT_WorkRect) { return window->WorkRect; }
+ else if (rect_type == RT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
+ else if (rect_type == RT_ContentsRegionRect) { return window->ContentsRegionRect; }
+ IM_ASSERT(0);
+ return ImRect();
+ }
+
static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
{
bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size);
@@ -9623,25 +9946,28 @@ void ImGui::ShowMetricsWindow(bool* p_open)
continue;
}
ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
- bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
+ char buf[300];
+ ImFormatString(buf, IM_ARRAYSIZE(buf), "Draw %4d triangles, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
+ pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
+ bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered())
{
ImRect clip_rect = pcmd->ClipRect;
ImRect vtxs_rect;
for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
- clip_rect.Floor(); fg_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
- vtxs_rect.Floor(); fg_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
+ clip_rect.Floor(); fg_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,0,255,255));
+ vtxs_rect.Floor(); fg_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,255,0,255));
}
if (!pcmd_node_open)
continue;
// Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
+ ImGui::Text("ElemCount: %d, ElemCount/3: %d, VtxOffset: +%d, IdxOffset: +%d", pcmd->ElemCount, pcmd->ElemCount/3, pcmd->VtxOffset, pcmd->IdxOffset);
ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
while (clipper.Step())
for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
{
- char buf[300];
char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
ImVec2 triangles_pos[3];
for (int n = 0; n < 3; n++, idx_i++)
@@ -9650,7 +9976,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImDrawVert& v = draw_list->VtxBuffer[vtx_i];
triangles_pos[n] = v.pos;
buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
- (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
+ (n == 0) ? "elem" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
}
ImGui::Selectable(buf, false);
if (fg_draw_list && ImGui::IsItemHovered())
@@ -9670,7 +9996,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
return;
- ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX);
+ ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm));
ImGui::TreePop();
@@ -9691,12 +10017,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return;
ImGuiWindowFlags flags = window->Flags;
NodeDrawList(window, window->DrawList, "DrawList");
- ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
+ ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y);
ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
(flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
(flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
(flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
- ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetWindowScrollMaxX(window), window->Scroll.y, GetWindowScrollMaxY(window));
+ ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y);
ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
@@ -9794,7 +10120,19 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
- show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, "OuterRect\0" "OuterRectClipped\0" "InnerMainRect\0" "InnerClipRect\0" "ContentsRegionRect\0");
+ const char* rects_names[RT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" };
+ show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, rects_names, RT_Count);
+ if (show_windows_rects && g.NavWindow)
+ {
+ ImGui::BulletText("'%s':", g.NavWindow->Name);
+ ImGui::Indent();
+ for (int n = 0; n < RT_Count; n++)
+ {
+ ImRect r = Funcs::GetRect(g.NavWindow, n);
+ ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), rects_names[n]);
+ }
+ ImGui::Unindent();
+ }
ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects);
ImGui::TreePop();
}
@@ -9809,12 +10147,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImDrawList* draw_list = GetForegroundDrawList(window);
if (show_windows_rects)
{
- ImRect r;
- if (show_windows_rect_type == RT_OuterRect) { r = window->Rect(); }
- else if (show_windows_rect_type == RT_OuterRectClipped) { r = window->OuterRectClipped; }
- else if (show_windows_rect_type == RT_InnerMainRect) { r = window->InnerMainRect; }
- else if (show_windows_rect_type == RT_InnerClipRect) { r = window->InnerClipRect; }
- else if (show_windows_rect_type == RT_ContentsRegionRect) { r = window->ContentsRegionRect; }
+ ImRect r = Funcs::GetRect(window, show_windows_rect_type);
draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
}
if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow))