1
0
mirror of https://github.com/Drezil/imgui.git synced 2025-03-13 16:32:42 +00:00

Added optional Horizontal Scrollbar & allow user to explicitly set content width via SetNextWindowContentSize() etc ()

GetCursorPos, SetCursorPos, GetContentRegionMax,
GetWindowContentRegionMin, GetWindowContentRegionMax are now including
the scrolling amount. It PROBABLY shouldn't break anything for you, but
take note that SetCursorPosX(100.0f) puts you at +100 from the starting
x position which may include scrolling, not at +100 from the window left
side.
This commit is contained in:
ocornut 2015-08-30 16:37:56 +01:00
parent 9eed672725
commit 65a191c005
3 changed files with 151 additions and 75 deletions

205
imgui.cpp

@ -140,6 +140,9 @@
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
Also read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with position:
GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.
GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!
- 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
- 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project.
- 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason
@ -537,7 +540,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWind
static inline bool IsWindowContentHoverable(ImGuiWindow* window);
static void ClearSetNextWindowData();
static void CheckStacksSize(ImGuiWindow* window, bool write);
static void Scrollbar(ImGuiWindow* window);
static void Scrollbar(ImGuiWindow* window, bool horizontal);
static bool CloseWindowButton(bool* p_opened);
static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDrawList* draw_list);
@ -1470,12 +1473,13 @@ ImGuiWindow::ImGuiWindow(const char* name)
Flags = 0;
PosFloat = Pos = ImVec2(0.0f, 0.0f);
Size = SizeFull = ImVec2(0.0f, 0.0f);
SizeContents = ImVec2(0.0f, 0.0f);
SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
WindowPadding = ImVec2(0.0f, 0.0f);
Scroll = ImVec2(0.0f, 0.0f);
ScrollTargetRelY = FLT_MAX;
ScrollTargetCenterRatioY = 0.5f;
ScrollbarY = false;
ScrollbarX = ScrollbarY = false;
ScrollbarSizes = ImVec2(0.0f, 0.0f);
Active = WasActive = false;
Accessed = false;
Collapsed = false;
@ -1576,7 +1580,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x - window->Scroll.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX), (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);
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
@ -1708,9 +1712,9 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
ImGuiWindow* window = GetCurrentWindowRead();
if (wrap_pos_x == 0.0f)
wrap_pos_x = ImGui::GetContentRegionMax().x;
if (wrap_pos_x > 0.0f)
wrap_pos_x += window->Pos.x; // wrap_pos_x is provided is window local space
wrap_pos_x = ImGui::GetContentRegionMax().x + window->Pos.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
const float wrap_width = wrap_pos_x > 0.0f ? ImMax(wrap_pos_x - pos.x, 0.00001f) : 0.0f;
return wrap_width;
@ -3083,7 +3087,7 @@ void ImGui::CloseCurrentPopup()
static void ClearSetNextWindowData()
{
ImGuiState& g = *GImGui;
g.SetNextWindowPosCond = g.SetNextWindowSizeCond = g.SetNextWindowCollapsedCond = g.SetNextWindowFocus = 0;
g.SetNextWindowPosCond = g.SetNextWindowSizeCond = g.SetNextWindowContentSizeCond = g.SetNextWindowCollapsedCond = g.SetNextWindowFocus = 0;
}
static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags)
@ -3429,6 +3433,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
const int current_frame = ImGui::GetFrameCount();
const bool first_begin_of_the_frame = (window->LastFrameDrawn != current_frame);
bool window_was_visible = (window->LastFrameDrawn == current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
if (flags & ImGuiWindowFlags_Popup)
{
@ -3466,6 +3471,15 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
ImGui::SetWindowSize(g.SetNextWindowSizeVal, g.SetNextWindowSizeCond);
g.SetNextWindowSizeCond = 0;
}
if (g.SetNextWindowContentSizeCond)
{
window->SizeContentsExplicit = g.SetNextWindowContentSizeVal;
g.SetNextWindowContentSizeCond = 0;
}
else if (first_begin_of_the_frame)
{
window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
}
if (g.SetNextWindowCollapsedCond)
{
if (!window_was_visible) window->SetWindowCollapsedAllowFlags |= ImGuiSetCond_Appearing;
@ -3494,7 +3508,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
bg_alpha = style.WindowFillAlphaDefault;
// When reusing window again multiple times a frame, just append content (don't need to setup again)
const bool first_begin_of_the_frame = (window->LastFrameDrawn != current_frame);
if (first_begin_of_the_frame)
{
window->Active = true;
@ -3548,9 +3561,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
// SIZE
// Save contents size from last frame for auto-fitting
window->SizeContents = window_is_new ? ImVec2(0.0f, 0.0f) : window->DC.CursorMaxPos - window->Pos;
window->SizeContents.y += window->Scroll.y;
// Save contents size from last frame for auto-fitting (unless explicitly specified)
window->SizeContents.x = (window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : ((window_is_new ? 0.0f : window->DC.CursorMaxPos.x - window->Pos.x) + window->Scroll.x);
window->SizeContents.y = (window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : ((window_is_new ? 0.0f : window->DC.CursorMaxPos.y - window->Pos.y) + window->Scroll.y);
// Hide popup/tooltip window when first appearing while we measure size (because we recycle them)
if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window_was_visible)
@ -3564,7 +3577,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
}
}
// Lock window padding so that altering the ShowBorders flag for childs doesn't have side-effects.
// Lock window padding so that altering the ShowBorders flag for children doesn't have side-effects.
window->WindowPadding = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : style.WindowPadding;
// Calculate auto-fit size
@ -3577,6 +3590,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
else
{
size_auto_fit = ImClamp(window->SizeContents + window->WindowPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - window->WindowPadding));
// Handling case of auto fit window not fitting in screen on one axis, we are growing auto fit size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding.
if (size_auto_fit.x < window->SizeContents.x && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar))
size_auto_fit.y += style.ScrollbarSize;
if (size_auto_fit.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar))
size_auto_fit.x += style.ScrollbarSize;
size_auto_fit.y = ImMax(size_auto_fit.y - style.ItemSpacing.y, 0.0f);
@ -3647,7 +3664,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
if (parent_window->DC.MenuBarAppending)
rect_to_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight());
else
rect_to_avoid = ImRect(parent_window->Pos.x + style.ItemSpacing.x, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - style.ItemSpacing.x - parent_window->ScrollbarWidth(), FLT_MAX); // We want some overlap to convey the relative depth of each popup (here hard-coded to 4)
rect_to_avoid = ImRect(parent_window->Pos.x + style.ItemSpacing.x, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - style.ItemSpacing.x - parent_window->ScrollbarSizes.x, FLT_MAX); // We want some overlap to convey the relative depth of each popup (here hard-coded to 4)
window->PosFloat = FindBestPopupWindowPos(window->PosFloat, window->Size, flags, &window->AutoPosLastDirection, rect_to_avoid);
}
else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_appearing_after_being_hidden)
@ -3716,9 +3733,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->Scroll.y = window->ScrollTargetRelY - ((1.0f - center_ratio_y) * window->TitleBarHeight()) - (center_ratio_y * window->SizeFull.y);
window->ScrollTargetRelY = FLT_MAX;
}
window->Scroll.y = ImMax(window->Scroll.y, 0.0f);
window->Scroll = ImMax(window->Scroll, ImVec2(0.0f, 0.0f));
if (!window->Collapsed && !window->SkipItems)
window->Scroll.y = ImMin(window->Scroll.y, ImMax(0.0f, window->SizeContents.y - window->SizeFull.y));
window->Scroll = ImMin(window->Scroll, ImMax(ImVec2(0.0f, 0.0f), window->SizeContents - window->SizeFull + window->ScrollbarSizes));
// Modal window darkens what is behind them
if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostModalRootWindow())
@ -3776,8 +3793,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
title_bar_rect = window->TitleBarRect();
}
// Scrollbar
// Scrollbars
window->ScrollbarX = (window->SizeContents.x > window->Size.x - style.ScrollbarSize - window->WindowPadding.x) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
window->ScrollbarY = (window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar);
window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
// Window background
if (bg_alpha > 0.0f)
@ -3789,7 +3808,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
else if ((flags & ImGuiWindowFlags_Popup) != 0)
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_WindowBg, bg_alpha), window_rounding);
else if ((flags & ImGuiWindowFlags_ChildWindow) != 0)
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size-ImVec2(window->ScrollbarWidth(),0.0f), window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF));
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size - window->ScrollbarSizes, window->Color(ImGuiCol_ChildWindowBg, bg_alpha), window_rounding, window->ScrollbarY ? (1|8) : (0xF));
else
window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, window->Color(ImGuiCol_WindowBg, bg_alpha), window_rounding);
}
@ -3814,9 +3833,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->DrawList->AddLine(title_bar_rect.GetBL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_Border));
}
// Scrollbar
// Scrollbars
if (window->ScrollbarX)
Scrollbar(window, true);
if (window->ScrollbarY)
Scrollbar(window);
Scrollbar(window, false);
// Render resize grip
// (after the input handling so we don't have a frame of latency)
@ -3833,7 +3854,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
// Setup drawing context
window->DC.ColumnsStartX = window->WindowPadding.x;
window->DC.ColumnsOffsetX = 0.0f;
window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y) - ImVec2(0.0f, window->Scroll.y);
window->DC.CursorStartPos = window->Pos - window->Scroll + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y);
window->DC.CursorPos = window->DC.CursorStartPos;
window->DC.CursorPosPrevLine = window->DC.CursorPos;
window->DC.CursorMaxPos = window->DC.CursorStartPos;
@ -3909,8 +3930,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
ImRect clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding.x*0.5f, title_bar_rect.Max.y+window->MenuBarHeight()+0.5f, window->Pos.x+window->Size.x+0.5f-window->WindowPadding.x*0.5f, window->Pos.y+window->Size.y+0.5f);
if ((flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_ShowBorders))
clip_rect.Min += ImVec2(1.0f,1.0f);
if (window->ScrollbarY)
clip_rect.Max.x -= style.ScrollbarSize;
clip_rect.Max.x -= window->ScrollbarY ? style.ScrollbarSize : 0.0f;
clip_rect.Max.y -= window->ScrollbarX ? style.ScrollbarSize : 0.0f;
PushClipRect(clip_rect);
// Clear 'accessed' flag last thing
@ -3965,23 +3986,34 @@ void ImGui::End()
// Vertical scrollbar
// The entire piece of code below is rather confusing because:
// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
// - We store values as ratio and in a form that allows the window content to change while we are holding on a scrollbar
static void Scrollbar(ImGuiWindow* window)
// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
static void Scrollbar(ImGuiWindow* window, bool horizontal)
{
ImGuiState& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID("#SCROLLY");
const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY");
// Render background
ImRect bb(window->Rect().Max.x - style.ScrollbarSize, window->Pos.y + window->TitleBarHeight()+1, window->Rect().Max.x, window->Rect().Max.y-1);
bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
const ImRect window_rect = window->Rect();
ImRect bb = horizontal
? ImRect(window->Pos.x + 1, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - 1 - other_scrollbar_size_w, window_rect.Max.y)
: ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + window->TitleBarHeight()+1, window_rect.Max.x, window_rect.Max.y - 1 - other_scrollbar_size_w);
window->DrawList->AddRectFilled(bb.Min, bb.Max, window->Color(ImGuiCol_ScrollbarBg));
bb.Expand(-3.0f);
const float scrollbar_height = bb.GetHeight();
// V denote the main axis of the scrollbar
float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y;
float win_size_avail_v = (horizontal ? window->Size.x : window->Size.y) - other_scrollbar_size_w;
float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y;
// The grabable box size generally represent the amount visible (vs the total scrollable amount)
// But we maintain a minimum size in pixel to allow for the user to still aim inside.
const float grab_h_pixels = ImMin(ImMax(scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y)), style.GrabMinSize), scrollbar_height);
const float grab_h_norm = grab_h_pixels / scrollbar_height;
const float grab_h_pixels = ImMin(ImMax(scrollbar_size_v * ImSaturate(win_size_avail_v / ImMax(win_size_contents_v, win_size_avail_v)), style.GrabMinSize), scrollbar_size_v);
const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
bool held = false;
@ -3989,46 +4021,58 @@ static void Scrollbar(ImGuiWindow* window)
const bool previously_held = (g.ActiveId == id);
ImGui::ButtonBehavior(bb, id, &hovered, &held, true);
const float scroll_max = ImMax(1.0f, window->SizeContents.y - window->Size.y);
float scroll_ratio = ImSaturate(window->Scroll.y / scroll_max);
float grab_y_norm = scroll_ratio * (scrollbar_height - grab_h_pixels) / scrollbar_height;
if (held)
float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
float scroll_ratio = ImSaturate(scroll_v / scroll_max);
float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
if (held && grab_h_norm < 1.0f)
{
const float clicked_y_norm = ImSaturate((g.IO.MousePos.y - bb.Min.y) / scrollbar_height); // Click position in scrollbar space (0.0f->1.0f)
float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y;
// Click position in scrollbar normalized space (0.0f->1.0f)
const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
g.HoveredId = id;
bool seek_absolute = false;
if (!previously_held)
{
// On initial click calculate the distance between mouse and the center of the grab
if (clicked_y_norm >= grab_y_norm && clicked_y_norm <= grab_y_norm + grab_h_norm)
if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm)
{
g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_y_norm - grab_h_norm*0.5f;
*click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
}
else
{
seek_absolute = true;
g.ScrollbarClickDeltaToGrabCenter = 0;
*click_delta_to_grab_center_v = 0.0f;
}
}
// Apply scroll
// It is ok to modify ScrollY here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
const float scroll_y_norm = ImSaturate((clicked_y_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
window->Scroll.y = (float)(int)(0.5f + scroll_y_norm * (window->SizeContents.y - window->Size.y));
// It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
if (horizontal)
window->Scroll.x = scroll_v;
else
window->Scroll.y = scroll_v;
// Update values for rendering
scroll_ratio = ImSaturate(window->Scroll.y / scroll_max);
grab_y_norm = scroll_ratio * (scrollbar_height - grab_h_pixels) / scrollbar_height;
scroll_ratio = ImSaturate(scroll_v / scroll_max);
grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
// Update distance to grab now that we have seeked and saturated
if (seek_absolute)
g.ScrollbarClickDeltaToGrabCenter = clicked_y_norm - grab_y_norm - grab_h_norm*0.5f;
*click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
}
// Render
const ImU32 grab_col = window->Color(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab);
window->DrawList->AddRectFilled(ImVec2(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_y_norm)), ImVec2(bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_y_norm) + grab_h_pixels), grab_col, style.ScrollbarRounding);
if (horizontal)
window->DrawList->AddRectFilled(ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y), ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y), grab_col, style.ScrollbarRounding);
else
window->DrawList->AddRectFilled(ImVec2(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm)), ImVec2(bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels), grab_col, style.ScrollbarRounding);
}
// Moving window to front of display (which happens to be back of our sorted list)
@ -4519,6 +4563,20 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond)
g.SetNextWindowSizeCond = cond ? cond : ImGuiSetCond_Always;
}
void ImGui::SetNextWindowContentSize(const ImVec2& size)
{
ImGuiState& g = *GImGui;
g.SetNextWindowContentSizeVal = size;
g.SetNextWindowContentSizeCond = ImGuiSetCond_Always;
}
void ImGui::SetNextWindowContentWidth(float width)
{
ImGuiState& g = *GImGui;
g.SetNextWindowContentSizeVal = ImVec2(width, g.SetNextWindowContentSizeCond ? g.SetNextWindowContentSizeVal.y : 0.0f);
g.SetNextWindowContentSizeCond = ImGuiSetCond_Always;
}
void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond)
{
ImGuiState& g = *GImGui;
@ -4536,11 +4594,13 @@ void ImGui::SetNextWindowFocus()
ImVec2 ImGui::GetContentRegionMax()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImVec2 mx = window->Size - window->WindowPadding;
ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x, window->SizeContentsExplicit.y ? window->SizeContentsExplicit.y : window->Size.y);
ImVec2 mx = content_region_size - window->Scroll - window->WindowPadding;
if (window->DC.ColumnsCount != 1)
mx.x = ImGui::GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x;
else
mx.x -= window->ScrollbarWidth();
mx.x -= window->ScrollbarSizes.x;
mx.y -= window->ScrollbarSizes.y;
return mx;
}
@ -4559,17 +4619,22 @@ float ImGui::GetContentRegionAvailWidth()
ImVec2 ImGui::GetWindowContentRegionMin()
{
ImGuiWindow* window = GetCurrentWindowRead();
return ImVec2(0, window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding;
return ImVec2(-window->Scroll.x, -window->Scroll.y + window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding;
}
ImVec2 ImGui::GetWindowContentRegionMax()
{
ImGuiWindow* window = GetCurrentWindowRead();
ImVec2 m = window->Size - window->WindowPadding;
m.x -= window->ScrollbarWidth();
ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x, window->SizeContentsExplicit.y ? window->SizeContentsExplicit.y : window->Size.y);
ImVec2 m = content_region_size - window->Scroll - window->WindowPadding - window->ScrollbarSizes;
return m;
}
float ImGui::GetWindowContentRegionWidth()
{
return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x;
}
float ImGui::GetTextLineHeight()
{
ImGuiState& g = *GImGui;
@ -4619,37 +4684,39 @@ void ImGui::SetWindowFontScale(float scale)
ImVec2 ImGui::GetCursorPos()
{
ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.CursorPos - window->Pos;
return window->DC.CursorPos - window->Pos + window->Scroll;
}
float ImGui::GetCursorPosX()
{
return ImGui::GetCursorPos().x;
ImGuiWindow* window = GetCurrentWindow();
return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
}
float ImGui::GetCursorPosY()
{
return ImGui::GetCursorPos().y;
ImGuiWindow* window = GetCurrentWindow();
return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
}
void ImGui::SetCursorPos(const ImVec2& local_pos)
{
ImGuiWindow* window = GetCurrentWindow();
window->DC.CursorPos = window->Pos + local_pos;
window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
}
void ImGui::SetCursorPosX(float x)
{
ImGuiWindow* window = GetCurrentWindow();
window->DC.CursorPos.x = window->Pos.x + x;
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
}
void ImGui::SetCursorPosY(float y)
{
ImGuiWindow* window = GetCurrentWindow();
window->DC.CursorPos.y = window->Pos.y + y;
window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
}
@ -6944,7 +7011,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
}
draw_window = GetCurrentWindow();
draw_window->DC.CursorPos += style.FramePadding;
size.x -= draw_window->ScrollbarWidth();
size.x -= draw_window->ScrollbarSizes.x;
}
else
{
@ -8388,7 +8455,7 @@ void ImGui::BeginGroup()
group_data.BackupLogLinePosY = window->DC.LogLinePosY;
group_data.AdvanceCursor = true;
window->DC.ColumnsStartX = window->DC.CursorPos.x - window->Pos.x;
window->DC.ColumnsStartX = window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
window->DC.CursorMaxPos = window->DC.CursorPos;
window->DC.CurrentLineHeight = 0.0f;
window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
@ -8442,7 +8509,7 @@ void ImGui::SameLine(float local_pos_x, float spacing_w)
if (local_pos_x != 0.0f)
{
if (spacing_w < 0.0f) spacing_w = 0.0f;
x = window->Pos.x + local_pos_x + spacing_w;
x = window->Pos.x - window->Scroll.x + local_pos_x + spacing_w;
y = window->DC.CursorPosPrevLine.y;
}
else
@ -8471,7 +8538,7 @@ void ImGui::NextColumn()
window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount)
{
window->DC.ColumnsOffsetX = ImGui::GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.ColumnsStartX + g.Style.ItemSpacing.x;
window->DC.ColumnsOffsetX = ImGui::GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.ColumnsStartX + window->Scroll.x + g.Style.ItemSpacing.x;
window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent);
}
else
@ -8481,7 +8548,7 @@ void ImGui::NextColumn()
window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY;
window->DrawList->ChannelsSetCurrent(0);
}
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX);
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.ColumnsStartX - window->Scroll.x + window->DC.ColumnsOffsetX);
window->DC.CursorPos.y = window->DC.ColumnsCellMinY;
window->DC.CurrentLineHeight = 0.0f;
window->DC.CurrentLineTextBaseOffset = 0.0f;
@ -8536,8 +8603,9 @@ float ImGui::GetColumnOffset(int column_index)
IM_ASSERT(column_index < window->DC.ColumnsOffsetsT.Size);
const float t = window->DC.ColumnsOffsetsT[column_index];
const float min_x = window->DC.ColumnsStartX;
const float max_x = window->Size.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
const float content_region_width = window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x;
const float min_x = window->DC.ColumnsStartX - window->Scroll.x;
const float max_x = content_region_width - window->Scroll.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
const float x = min_x + t * (max_x - min_x);
return (float)(int)x;
}
@ -8552,8 +8620,9 @@ void ImGui::SetColumnOffset(int column_index, float offset)
IM_ASSERT(column_index < window->DC.ColumnsOffsetsT.Size);
const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index);
const float min_x = window->DC.ColumnsStartX;
const float max_x = window->Size.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
const float content_region_width = window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x;
const float min_x = window->DC.ColumnsStartX - window->Scroll.x;
const float max_x = content_region_width - window->Scroll.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
const float t = (offset - min_x) / (max_x - min_x);
window->DC.StateStorage->SetFloat(column_id, t);
window->DC.ColumnsOffsetsT[column_index] = t;
@ -8641,7 +8710,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
window->DC.ColumnsStartPos = window->DC.CursorPos;
window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.CursorPos.y;
window->DC.ColumnsOffsetX = 0.0f;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX);
window->DC.CursorPos.x = (float)(int)(window->Pos.x - window->Scroll.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX);
if (window->DC.ColumnsCount != 1)
{
@ -8672,7 +8741,7 @@ void ImGui::Indent()
ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->DC.ColumnsStartX += g.Style.IndentSpacing;
window->DC.CursorPos.x = window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX;
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX;
}
void ImGui::Unindent()
@ -8680,7 +8749,7 @@ void ImGui::Unindent()
ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->DC.ColumnsStartX -= g.Style.IndentSpacing;
window->DC.CursorPos.x = window->Pos.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX;
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + window->DC.ColumnsStartX + window->DC.ColumnsOffsetX;
}
void ImGui::TreePush(const char* str_id)

10
imgui.h

@ -120,11 +120,12 @@ namespace ImGui
IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400).
IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // "
IMGUI_API void EndChild();
IMGUI_API ImVec2 GetContentRegionMax(); // window or current column boundaries, in windows coordinates
IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates
IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos()
IMGUI_API ImVec2 GetWindowContentRegionMin(); // window boundaries, in windows coordinates
IMGUI_API ImVec2 GetWindowContentRegionMax();
IMGUI_API float GetContentRegionAvailWidth(); //
IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates
IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates
IMGUI_API float GetWindowContentRegionWidth(); //
IMGUI_API ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives
IMGUI_API ImFont* GetWindowFont();
IMGUI_API float GetWindowFontSize(); // size (also height in pixels) of current font with current scale applied
@ -138,6 +139,8 @@ namespace ImGui
IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position. call before Begin()
IMGUI_API void SetNextWindowPosCenter(ImGuiSetCond cond = 0); // set next window position to be centered on screen. call before Begin()
IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin()
IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (enforce the range of scrollbars). set axis to 0.0f to leave it automatic. call before Begin()
IMGUI_API void SetNextWindowContentWidth(float width); // set next window content width (enforce the range of horizontal scrollbar). call before Begin()
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state. call before Begin()
IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin()
IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set current window position - call within Begin()/End(). may incur tearing
@ -449,6 +452,7 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file
ImGuiWindowFlags_NoInputs = 1 << 9, // Disable catching mouse or keyboard inputs
ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar
ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Enable horizontal scrollbar (off by default). You need to use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section.
// [Internal]
ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild()
ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild()

@ -359,9 +359,11 @@ struct ImGuiState
// Storage for SetNexWindow** and SetNextTreeNode*** functions
ImVec2 SetNextWindowPosVal;
ImVec2 SetNextWindowSizeVal;
ImVec2 SetNextWindowContentSizeVal;
bool SetNextWindowCollapsedVal;
ImGuiSetCond SetNextWindowPosCond;
ImGuiSetCond SetNextWindowSizeCond;
ImGuiSetCond SetNextWindowContentSizeCond;
ImGuiSetCond SetNextWindowCollapsedCond;
bool SetNextWindowFocus;
bool SetNextTreeNodeOpenedVal;
@ -384,7 +386,7 @@ struct ImGuiState
float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
float DragSpeedScaleSlow;
float DragSpeedScaleFast;
float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space
ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
char Tooltip[1024];
char* PrivateClipboard; // If no custom clipboard handler is defined
@ -446,7 +448,7 @@ struct ImGuiState
DragSpeedDefaultRatio = 0.01f;
DragSpeedScaleSlow = 0.01f;
DragSpeedScaleFast = 10.0f;
ScrollbarClickDeltaToGrabCenter = 0.0f;
ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f);
memset(Tooltip, 0, sizeof(Tooltip));
PrivateClipboard = NULL;
@ -558,12 +560,14 @@ struct ImGuiWindow
ImVec2 Size; // Current size (==SizeFull or collapsed title bar size)
ImVec2 SizeFull; // Size when non collapsed
ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame
ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize()
ImVec2 WindowPadding; // Window padding at the time of begin. We need to lock it, in particular manipulation of the ShowBorder would have an effect
ImGuiID MoveID; // == window->GetID("#MOVE")
ImVec2 Scroll;
float ScrollTargetRelY; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)
float ScrollTargetCenterRatioY; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered
bool ScrollbarY;
bool ScrollbarX, ScrollbarY;
ImVec2 ScrollbarSizes; //
bool Active; // Set to true on Begin()
bool WasActive;
bool Accessed; // Set to true when any widget access the current window
@ -614,7 +618,6 @@ public:
ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; }
ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
float ScrollbarWidth() const { return ScrollbarY ? GImGui->Style.ScrollbarSize : 0.0f; }
ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); }
ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }
};