Merge branch 'master' into docking

# Conflicts:
#	docs/CHANGELOG.txt
#	imgui.cpp
This commit is contained in:
omar
2019-07-02 18:47:10 +02:00
10 changed files with 277 additions and 160 deletions

273
imgui.cpp
View File

@ -855,6 +855,8 @@ CODE
main font. Then you can refer to icons within your strings.
You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment.
(Read the 'misc/fonts/README.txt' file for more details about icons font loading.)
With some extra effort, you may use colorful icon by registering custom rectangle space inside the font atlas,
and copying your own graphics data into it. See misc/fonts/README.txt about using the AddCustomRectFontGlyph API.
Q: How can I load multiple fonts?
A: Use the font atlas to pack them into a single texture:
@ -2282,20 +2284,64 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
//-----------------------------------------------------------------------------
// [SECTION] ImGuiListClipper
// This is currently not as flexible/powerful as it should be, needs some rework (see TODO)
// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed
// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)
//-----------------------------------------------------------------------------
// Helper to calculate coarse clipping of large list of evenly sized items.
// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.LogEnabled)
{
// If logging is active, do not perform any clipping
*out_items_display_start = 0;
*out_items_display_end = items_count;
return;
}
if (window->SkipItems)
{
*out_items_display_start = *out_items_display_end = 0;
return;
}
// We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
ImRect unclipped_rect = window->ClipRect;
if (g.NavMoveRequest)
unclipped_rect.Add(g.NavScoringRectScreen);
const ImVec2 pos = window->DC.CursorPos;
int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
// When performing a navigation request, ensure we have one item extra in the direction we are moving to
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
start--;
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
end++;
start = ImClamp(start, 0, items_count);
end = ImClamp(end + 1, start, items_count);
*out_items_display_start = start;
*out_items_display_end = end;
}
static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
{
// Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
// FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
// The clipper should probably have a 4th step to display the last item in a regular manner.
ImGui::SetCursorPosY(pos_y);
ImGuiWindow* window = ImGui::GetCurrentWindow();
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
window->DC.PrevLineSize.y = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
window->DC.CursorPos.y = pos_y;
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
if (ImGuiColumns* columns = window->DC.CurrentColumns)
columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
}
// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
@ -2303,7 +2349,10 @@ static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style.
void ImGuiListClipper::Begin(int count, float items_height)
{
StartPosY = ImGui::GetCursorPosY();
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
StartPosY = window->DC.CursorPos.y;
ItemsHeight = items_height;
ItemsCount = count;
StepNo = 0;
@ -2330,7 +2379,10 @@ void ImGuiListClipper::End()
bool ImGuiListClipper::Step()
{
if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (ItemsCount == 0 || window->SkipItems)
{
ItemsCount = -1;
return false;
@ -2339,16 +2391,16 @@ bool ImGuiListClipper::Step()
{
DisplayStart = 0;
DisplayEnd = 1;
StartPosY = ImGui::GetCursorPosY();
StartPosY = window->DC.CursorPos.y;
StepNo = 1;
return true;
}
if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
{
if (ItemsCount == 1) { ItemsCount = -1; return false; }
float items_height = ImGui::GetCursorPosY() - StartPosY;
float items_height = window->DC.CursorPos.y - StartPosY;
IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
Begin(ItemsCount-1, items_height);
Begin(ItemsCount - 1, items_height);
DisplayStart++;
DisplayEnd++;
StepNo = 3;
@ -3414,7 +3466,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
g.MovingWindow = NULL;
}
else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL)
else if (g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
{
// Clicking on void disable focus
FocusWindow(NULL);
@ -3426,9 +3478,9 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
// (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
if (g.IO.MouseClicked[1])
{
// Find the top-most window between HoveredWindow and the front most Modal Window.
// Find the top-most window between HoveredWindow and the top-most Modal Window.
// This is where we can trim the popup stack.
ImGuiWindow* modal = GetFrontMostPopupModal();
ImGuiWindow* modal = GetTopMostPopupModal();
bool hovered_window_above_modal = false;
if (modal == NULL)
hovered_window_above_modal = true;
@ -3535,12 +3587,12 @@ void ImGui::UpdateMouseWheel()
return;
if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
return;
ImGuiWindow* window = g.HoveredWindow;
// 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 && !window->Collapsed)
if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling && !g.HoveredWindow->Collapsed)
{
ImGuiWindow* window = g.HoveredWindow;
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;
window->FontWindowScale = new_font_scale;
@ -3555,31 +3607,36 @@ void ImGui::UpdateMouseWheel()
}
// Mouse wheel scrolling
// If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set).
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs) && window->ParentWindow)
window = window->ParentWindow;
const bool scroll_allowed = !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
if (scroll_allowed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f) && !g.IO.KeyCtrl)
// If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
// FIXME: Lock scrolling window while not moving (see #2604)
// Vertical Mouse Wheel scrolling
const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
if (wheel_y != 0.0f && !g.IO.KeyCtrl)
{
ImVec2 max_step = window->InnerRect.GetSize() * 0.67f;
// Vertical Mouse Wheel Scrolling (hold Shift to scroll horizontally)
if (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift)
ImGuiWindow* window = g.HoveredWindow;
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
window = window->ParentWindow;
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
{
float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step.y));
SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * scroll_step);
}
else if (g.IO.MouseWheel != 0.0f && g.IO.KeyShift)
{
float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step.x));
SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheel * scroll_step);
float max_step = window->InnerRect.GetHeight() * 0.67f;
float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
SetWindowScrollY(window, window->Scroll.y - wheel_y * scroll_step);
}
}
// Horizontal Mouse Wheel Scrolling (for hardware that supports it)
if (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift)
// Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
if (wheel_x != 0.0f && !g.IO.KeyCtrl)
{
ImGuiWindow* window = g.HoveredWindow;
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
window = window->ParentWindow;
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
{
float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step.x));
SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_step);
float max_step = window->InnerRect.GetWidth() * 0.67f;
float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
SetWindowScrollX(window, window->Scroll.x - wheel_x * scroll_step);
}
}
}
@ -3597,7 +3654,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
IM_ASSERT(g.HoveredWindow == NULL || g.HoveredWindow == g.MovingWindow || g.HoveredWindow->Viewport == g.MouseViewport);
// Modal windows prevents cursor from hovering behind them.
ImGuiWindow* modal_window = GetFrontMostPopupModal();
ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window)
if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
@ -3838,7 +3895,7 @@ void ImGui::NewFrame()
UpdateMouseMovingWindowNewFrame();
// Background darkening/whitening
if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
else
g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
@ -4179,7 +4236,7 @@ static void ImGui::EndFrameDrawDimmedBackgrounds()
ImGuiContext& g = *GImGui;
// Draw modal whitening background on _other_ viewports than the one the modal is one
ImGuiWindow* modal_window = GetFrontMostPopupModal();
ImGuiWindow* modal_window = GetTopMostPopupModal();
const bool dim_bg_for_modal = (modal_window != NULL);
const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL);
if (dim_bg_for_modal || dim_bg_for_window_list)
@ -4345,18 +4402,18 @@ void ImGui::Render()
AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));
}
ImGuiWindow* windows_to_render_front_most[2];
windows_to_render_front_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
windows_to_render_front_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL;
ImGuiWindow* windows_to_render_top_most[2];
windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
windows_to_render_top_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL;
for (int n = 0; n != g.Windows.Size; n++)
{
ImGuiWindow* window = g.Windows[n];
if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_front_most[0] && window != windows_to_render_front_most[1])
if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
AddRootWindowToDrawData(window);
}
for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_front_most); n++)
if (windows_to_render_front_most[n] && IsWindowActiveAndVisible(windows_to_render_front_most[n])) // NavWindowingTarget is always temporarily displayed as the front-most window
AddRootWindowToDrawData(windows_to_render_front_most[n]);
for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the tp-most window
AddRootWindowToDrawData(windows_to_render_top_most[n]);
// Draw software mouse cursor if requested
if (g.IO.MouseDrawCursor)
@ -4406,47 +4463,6 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex
return text_size;
}
// Helper to calculate coarse clipping of large list of evenly sized items.
// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.LogEnabled)
{
// If logging is active, do not perform any clipping
*out_items_display_start = 0;
*out_items_display_end = items_count;
return;
}
if (window->SkipItems)
{
*out_items_display_start = *out_items_display_end = 0;
return;
}
// We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
ImRect unclipped_rect = window->ClipRect;
if (g.NavMoveRequest)
unclipped_rect.Add(g.NavScoringRectScreen);
const ImVec2 pos = window->DC.CursorPos;
int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
// When performing a navigation request, ensure we have one item extra in the direction we are moving to
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
start--;
if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
end++;
start = ImClamp(start, 0, items_count);
end = ImClamp(end + 1, start, items_count);
*out_items_display_start = start;
*out_items_display_end = end;
}
// Find window given position, search front-to-back
// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically
// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
@ -5172,7 +5188,12 @@ 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->InnerRect.GetWidth();
float target_x = window->ScrollTarget.x;
if (snap_on_edges && cr_x <= 0.0f && target_x <= window->WindowPadding.x)
target_x = 0.0f;
else if (snap_on_edges && cr_x >= 1.0f && target_x >= window->ContentSize.x + window->WindowPadding.x + GImGui->Style.ItemSpacing.x)
target_x = window->ContentSize.x + window->WindowPadding.x * 2.0f;
scroll.x = target_x - cr_x * window->InnerRect.GetWidth();
}
if (window->ScrollTarget.y < FLT_MAX)
{
@ -6167,7 +6188,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
PushClipRect(host_rect.Min, host_rect.Max, false);
// Draw modal or window list full viewport dimming background (for other viewports we'll render them in EndFrame)
const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && ((window == g.NavWindowingTargetAnim->RootWindow) || (g.NavWindowingList && (window == g.NavWindowingList) && g.NavWindowingList->Viewport != g.NavWindowingTargetAnim->Viewport));
if (dim_bg_for_modal || dim_bg_for_window_list)
{
@ -6400,9 +6421,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
window->HiddenFramesCanSkipItems = 1;
// Completely hide along with parent or if parent is collapsed
if (parent_window && (parent_window->Collapsed || parent_window->Hidden))
// Hide along with parent or if parent is collapsed
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
window->HiddenFramesCanSkipItems = 1;
if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
window->HiddenFramesCannotSkipItems = 1;
}
// Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)
@ -6480,7 +6503,7 @@ void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
ImGuiContext& g = *GImGui;
if (g.WindowsFocusOrder.back() == window)
return;
for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the front most window
for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window
if (g.WindowsFocusOrder[i] == window)
{
memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
@ -6495,7 +6518,7 @@ void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
ImGuiWindow* current_front_window = g.Windows.back();
if (current_front_window == window || current_front_window->RootWindow == window)
return;
for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window
for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
if (g.Windows[i] == window)
{
memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
@ -7502,6 +7525,15 @@ void ImGui::SetScrollY(float scroll_y)
window->ScrollTargetCenterRatio.y = 0.0f;
}
void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
{
// We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
window->ScrollTarget.x = (float)(int)(local_x + window->Scroll.x);
window->ScrollTargetCenterRatio.x = center_x_ratio;
}
void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
{
// We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
@ -7511,6 +7543,16 @@ void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
window->ScrollTargetCenterRatio.y = center_y_ratio;
}
// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
void ImGui::SetScrollHereX(float center_x_ratio)
{
ImGuiWindow* window = GetCurrentWindow();
float target_x = window->DC.LastItemRect.Min.x - window->Pos.x; // Left of last item, in window space
float last_item_width = window->DC.LastItemRect.GetWidth();
target_x += (last_item_width * center_x_ratio) + (GImGui->Style.ItemSpacing.x * (center_x_ratio - 0.5f) * 2.0f); // Precisely aim before, in the middle or after the last item.
SetScrollFromPosX(target_x, center_x_ratio);
}
// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
void ImGui::SetScrollHereY(float center_y_ratio)
{
@ -7841,7 +7883,7 @@ bool ImGui::IsPopupOpen(const char* str_id)
return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
}
ImGuiWindow* ImGui::GetFrontMostPopupModal()
ImGuiWindow* ImGui::GetTopMostPopupModal()
{
ImGuiContext& g = *GImGui;
for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
@ -9118,7 +9160,7 @@ static void ImGui::NavUpdateWindowing()
ImGuiWindow* apply_focus_window = NULL;
bool apply_toggle_layer = false;
ImGuiWindow* modal_window = GetFrontMostPopupModal();
ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window != NULL)
{
g.NavWindowingTarget = NULL;
@ -9160,7 +9202,7 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingHighlightAlpha = 1.0f;
}
// Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most)
// Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
if (!IsNavInputDown(ImGuiNavInput_Menu))
{
g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
@ -14592,6 +14634,7 @@ void ImGui::ShowViewportThumbnails()
ImGui::Dummy(bb_full.GetSize() * SCALE);
}
#ifndef IMGUI_DISABLE_METRICS_WINDOW
void ImGui::ShowMetricsWindow(bool* p_open)
{
if (!ImGui::Begin("Dear ImGui Metrics", p_open))
@ -14600,10 +14643,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return;
}
enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect, RT_Count };
enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Contents, WRT_ContentsRegionRect, WRT_Count }; // Windows Rect Type
const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" };
static bool show_windows_begin_order = false;
static bool show_windows_rects = false;
static int show_windows_rect_type = RT_WorkRect;
static int show_windows_rect_type = WRT_WorkRect;
static bool show_drawcmd_clip_rects = true;
ImGuiIO& io = ImGui::GetIO();
@ -14616,15 +14661,15 @@ void ImGui::ShowMetricsWindow(bool* p_open)
struct Funcs
{
static ImRect GetRect(ImGuiWindow* window, int rect_type)
static ImRect GetWindowRect(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; }
if (rect_type == WRT_OuterRect) { return window->Rect(); }
else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; }
else if (rect_type == WRT_InnerRect) { return window->InnerRect; }
else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; }
else if (rect_type == WRT_WorkRect) { return window->WorkRect; }
else if (rect_type == WRT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
else if (rect_type == WRT_ContentsRegionRect) { return window->ContentsRegionRect; }
IM_ASSERT(0);
return ImRect();
}
@ -14849,16 +14894,15 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
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);
show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count);
if (show_windows_rects && g.NavWindow)
{
ImGui::BulletText("'%s':", g.NavWindow->Name);
ImGui::Indent();
for (int n = 0; n < RT_Count; n++)
for (int rect_n = 0; rect_n < WRT_Count; rect_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]);
ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_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(), wrt_rects_names[rect_n]);
}
ImGui::Unindent();
}
@ -14876,7 +14920,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImDrawList* draw_list = GetForegroundDrawList(window);
if (show_windows_rects)
{
ImRect r = Funcs::GetRect(window, show_windows_rect_type);
ImRect r = Funcs::GetWindowRect(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))
@ -14891,6 +14935,11 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
ImGui::End();
}
#else
void ImGui::ShowMetricsWindow(bool*)
{
}
#endif
void ImGui::ShowDockingDebug()
{