diff --git a/3rdparty/ocornut-imgui/imgui.cpp b/3rdparty/ocornut-imgui/imgui.cpp index 6c77f77bb..82e976045 100644 --- a/3rdparty/ocornut-imgui/imgui.cpp +++ b/3rdparty/ocornut-imgui/imgui.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.45 WIP +// ImGui library v1.45 // Main code & documentation // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. @@ -140,6 +140,10 @@ 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 - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. @@ -387,7 +391,6 @@ - window: resizing from any sides? + mouse cursor directives for app. - window: get size/pos helpers given names (see discussion in #249) - window: a collapsed window can be stuck behind the main menu bar? - - scrolling: add horizontal scroll !- scrolling: allow immediately effective change of scroll if we haven't appended items yet - widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. - widgets: clean up widgets internal toward exposing everything. @@ -536,7 +539,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& out_render_list, ImDrawList* draw_list); @@ -612,8 +615,8 @@ ImGuiStyle::ImGuiStyle() WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin() IndentSpacing = 22.0f; // Horizontal spacing when e.g. entering a tree node ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns - ScrollbarWidth = 16.0f; // Width of the vertical scrollbar - ScrollbarRounding = 0.0f; // Radius of grab corners rounding for scrollbar + ScrollbarSize = 16.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. DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows. @@ -634,7 +637,7 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); Colors[ImGuiCol_TitleBgActive] = ImVec4(0.50f, 0.50f, 1.00f, 0.55f); - Colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.60f); + Colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.40f, 0.80f, 0.15f); Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); @@ -1469,12 +1472,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); - ScrollY = 0.0f; - ScrollTargetRelY = FLT_MAX; - ScrollTargetCenterRatioY = 0.5f; - ScrollbarY = false; + Scroll = ImVec2(0.0f, 0.0f); + ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); + ScrollbarX = ScrollbarY = false; + ScrollbarSizes = ImVec2(0.0f, 0.0f); Active = WasActive = false; Accessed = false; Collapsed = false; @@ -1532,14 +1536,6 @@ ImGuiID ImGuiWindow::GetID(const void* ptr) // Internal API exposed in imgui_internal.h //----------------------------------------------------------------------------- -ImGuiWindow* ImGui::GetCurrentWindow() -{ - // If this ever crash it probably means that ImGui::NewFrame() has never been called (which is illegal). We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) - ImGuiState& g = *GImGui; - g.CurrentWindow->Accessed = true; - return g.CurrentWindow; -} - static void SetCurrentWindow(ImGuiWindow* window) { ImGuiState& g = *GImGui; @@ -1637,7 +1633,7 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id) bool ImGui::IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when_logged) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); if (!bb.Overlaps(window->ClipRect)) { @@ -1653,7 +1649,7 @@ bool ImGui::IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs) ImGuiState& g = *GImGui; if (g.HoveredId == 0 || g.HoveredId == id) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); if (g.HoveredWindow == window || (flatten_childs && g.HoveredRootWindow == window->RootWindow)) if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && ImGui::IsMouseHoveringRect(bb.Min, bb.Max)) if (IsWindowContentHoverable(g.HoveredRootWindow)) @@ -1713,11 +1709,11 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) if (wrap_pos_x < 0.0f) return 0.0f; - ImGuiWindow* window = ImGui::GetCurrentWindow(); + 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; @@ -1791,7 +1787,7 @@ void ImGui::NewFrame() IM_ASSERT(g.IO.RenderDrawListsFn != NULL); // Must be implemented IM_ASSERT(g.IO.Fonts->Fonts.Size > 0); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? - IM_ASSERT(g.Style.CurveTessellationTol > 0.0f); // Invalid + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f); // Invalid if (!g.Initialized) { @@ -1946,7 +1942,7 @@ void ImGui::NewFrame() if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse)) { const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5; - SetWindowScrollY(window, window->ScrollY - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines); + SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines); } } } @@ -2427,7 +2423,7 @@ void ImGui::LogText(const char* fmt, ...) static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* text_end) { ImGuiState& g = *GImGui; - ImGuiWindow* window = ImGui::GetCurrentWindow(); + ImGuiWindow* window = ImGui::GetCurrentWindowRead(); if (!text_end) text_end = FindTextDisplayEnd(text, text_end); @@ -2665,7 +2661,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); if (g.LogEnabled) { // If logging is active, do not perform any clipping @@ -2711,7 +2707,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs) bool ImGui::IsMouseHoveringRect(const ImVec2& pos_min, const ImVec2& pos_max) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); // Clip ImRect rect_clipped(pos_min, pos_max); @@ -2725,8 +2721,7 @@ bool ImGui::IsMouseHoveringRect(const ImVec2& pos_min, const ImVec2& pos_max) bool ImGui::IsMouseHoveringWindow() { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); - return g.HoveredWindow == window; + return g.HoveredWindow == g.CurrentWindow; } bool ImGui::IsMouseHoveringAnyWindow() @@ -2893,13 +2888,13 @@ void ImGui::CaptureMouseFromApp() bool ImGui::IsItemHovered() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.LastItemHoveredAndUsable; } bool ImGui::IsItemHoveredRect() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.LastItemHoveredRect; } @@ -2908,7 +2903,7 @@ bool ImGui::IsItemActive() ImGuiState& g = *GImGui; if (g.ActiveId) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return g.ActiveId == window->DC.LastItemID; } return false; @@ -2926,32 +2921,32 @@ bool ImGui::IsAnyItemActive() bool ImGui::IsItemVisible() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); ImRect r(window->ClipRect); return r.Overlaps(window->DC.LastItemRect); } ImVec2 ImGui::GetItemRectMin() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.LastItemRect.Min; } ImVec2 ImGui::GetItemRectMax() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.LastItemRect.Max; } ImVec2 ImGui::GetItemRectSize() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.LastItemRect.GetSize(); } ImVec2 ImGui::CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge, float outward) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); ImRect rect = window->DC.LastItemRect; rect.Expand(outward); return rect.GetClosestPoint(pos, on_edge); @@ -2989,7 +2984,7 @@ void ImGui::BeginTooltip() void ImGui::EndTooltip() { - IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Tooltip); + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); ImGui::End(); } @@ -3004,7 +2999,7 @@ static bool IsPopupOpen(ImGuiID id) void ImGui::OpenPopup(const char* str_id) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = g.CurrentWindow; ImGuiID id = window->GetID(str_id); int current_stack_size = g.CurrentPopupStack.Size; ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus"), g.IO.MousePos); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here) @@ -3091,7 +3086,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) @@ -3193,7 +3188,7 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow; const ImVec2 content_avail = ImGui::GetContentRegionAvail(); - ImVec2 size = size_arg; + ImVec2 size = ImRound(size_arg); if (size.x <= 0.0f) { if (size.x == 0.0f) @@ -3427,7 +3422,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window = CreateNewWindow(name, size_on_first_use, flags); window_is_new = true; } - window->Flags = (ImGuiWindowFlags)flags; + + const int current_frame = ImGui::GetFrameCount(); + const bool first_begin_of_the_frame = (window->LastFrameDrawn != current_frame); + if (first_begin_of_the_frame) + window->Flags = (ImGuiWindowFlags)flags; + else + flags = window->Flags; // Add to stack ImGuiWindow* parent_window = !g.CurrentWindowStack.empty() ? g.CurrentWindowStack.back() : NULL; @@ -3436,7 +3437,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ CheckStacksSize(window, true); IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); - const int current_frame = ImGui::GetFrameCount(); 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) { @@ -3474,6 +3474,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; @@ -3502,7 +3511,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; @@ -3556,9 +3564,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->ScrollY; + // 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) @@ -3572,7 +3580,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 @@ -3585,8 +3593,12 @@ 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.ScrollbarWidth; + size_auto_fit.x += style.ScrollbarSize; size_auto_fit.y = ImMax(size_auto_fit.y - style.ItemSpacing.y, 0.0f); } @@ -3655,7 +3667,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) @@ -3718,15 +3730,20 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; // Apply scrolling - if (window->ScrollTargetRelY < FLT_MAX) + if (window->ScrollTarget.x < FLT_MAX) { - float center_ratio_y = window->ScrollTargetCenterRatioY; - window->ScrollY = window->ScrollTargetRelY - ((1.0f - center_ratio_y) * window->TitleBarHeight()) - (center_ratio_y * window->SizeFull.y); - window->ScrollTargetRelY = FLT_MAX; + window->Scroll.x = window->ScrollTarget.x; + window->ScrollTarget.x = FLT_MAX; } - window->ScrollY = ImMax(window->ScrollY, 0.0f); + if (window->ScrollTarget.y < FLT_MAX) + { + float center_ratio = window->ScrollTargetCenterRatio.y; + window->Scroll.y = window->ScrollTarget.y - ((1.0f - center_ratio) * window->TitleBarHeight()) - (center_ratio * window->SizeFull.y); + window->ScrollTarget.y = FLT_MAX; + } + window->Scroll = ImMax(window->Scroll, ImVec2(0.0f, 0.0f)); if (!window->Collapsed && !window->SkipItems) - window->ScrollY = ImMin(window->ScrollY, 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()) @@ -3784,8 +3801,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ title_bar_rect = window->TitleBarRect(); } - // Scrollbar + // Scrollbars window->ScrollbarY = (window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarX = (window->SizeContents.x > window->Size.x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f) - window->WindowPadding.x) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); + window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); // Window background if (bg_alpha > 0.0f) @@ -3797,7 +3816,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); } @@ -3822,9 +3841,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) @@ -3839,16 +3860,16 @@ 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.ColumnsStartX = 0.0f + window->WindowPadding.x - window->Scroll.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->ScrollY); + window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + 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.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f; window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.MenuBarAppending = false; - window->DC.MenuBarOffsetX = ImMax(window->DC.ColumnsStartX, style.ItemSpacing.x); + window->DC.MenuBarOffsetX = ImMax(window->WindowPadding.x, style.ItemSpacing.x); window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); window->DC.LayoutType = ImGuiLayoutType_Vertical; @@ -3909,7 +3930,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ ImGui::LogToClipboard(); */ } - window->BeginCount++; // Inner clipping rectangle // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame @@ -3918,13 +3938,14 @@ 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.ScrollbarWidth; + 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 if (first_begin_of_the_frame) window->Accessed = false; + window->BeginCount++; // Child window can be out of sight and have "negative" clip windows. // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar). @@ -3973,23 +3994,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.ScrollbarWidth, 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; @@ -3997,46 +4029,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->ScrollY / 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->ScrollY = (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->ScrollY / 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) @@ -4102,7 +4146,7 @@ void ImGui::PopItemWidth() float ImGui::CalcItemWidth() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); float w = window->DC.ItemWidth; if (w < 0.0f) { @@ -4377,9 +4421,9 @@ ImVec2 ImGui::GetWindowPos() static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y) { - window->DC.CursorMaxPos.y += window->ScrollY; - window->ScrollY = new_scroll_y; - window->DC.CursorMaxPos.y -= window->ScrollY; + window->DC.CursorMaxPos.y += window->Scroll.y; + window->Scroll.y = new_scroll_y; + window->DC.CursorMaxPos.y -= window->Scroll.y; } static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiSetCond cond) @@ -4413,7 +4457,7 @@ void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond) ImVec2 ImGui::GetWindowSize() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->Size; } @@ -4449,8 +4493,7 @@ static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiSetCond void ImGui::SetWindowSize(const ImVec2& size, ImGuiSetCond cond) { - ImGuiWindow* window = GetCurrentWindow(); - SetWindowSize(window, size, cond); + SetWindowSize(GImGui->CurrentWindow, size, cond); } void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond) @@ -4473,8 +4516,7 @@ static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiSetCond void ImGui::SetWindowCollapsed(bool collapsed, ImGuiSetCond cond) { - ImGuiWindow* window = GetCurrentWindow(); - SetWindowCollapsed(window, collapsed, cond); + SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); } bool ImGui::IsWindowCollapsed() @@ -4491,8 +4533,7 @@ void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond co void ImGui::SetWindowFocus() { - ImGuiWindow* window = GetCurrentWindow(); - FocusWindow(window); + FocusWindow(GImGui->CurrentWindow); } void ImGui::SetWindowFocus(const char* name) @@ -4530,6 +4571,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; @@ -4546,36 +4601,45 @@ void ImGui::SetNextWindowFocus() // In window space (not screen space!) ImVec2 ImGui::GetContentRegionMax() { - ImGuiWindow* window = GetCurrentWindow(); - ImVec2 mx = window->Size - window->WindowPadding; + ImGuiWindow* window = GetCurrentWindowRead(); + ImVec2 content_region_size = ImVec2(window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x - window->ScrollbarSizes.x, window->SizeContentsExplicit.y ? window->SizeContentsExplicit.y : window->Size.y - window->ScrollbarSizes.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(); return mx; } ImVec2 ImGui::GetContentRegionAvail() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return GetContentRegionMax() - (window->DC.CursorPos - window->Pos); } +float ImGui::GetContentRegionAvailWidth() +{ + return GetContentRegionAvail().x; +} + // In window space (not screen space!) ImVec2 ImGui::GetWindowContentRegionMin() { - ImGuiWindow* window = GetCurrentWindow(); - return ImVec2(0, window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding; + ImGuiWindow* window = GetCurrentWindowRead(); + return ImVec2(-window->Scroll.x, -window->Scroll.y + window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding; } ImVec2 ImGui::GetWindowContentRegionMax() { - ImGuiWindow* window = GetCurrentWindow(); - ImVec2 m = window->Size - window->WindowPadding; - m.x -= window->ScrollbarWidth(); + ImGuiWindow* window = GetCurrentWindowRead(); + 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; @@ -4624,50 +4688,52 @@ void ImGui::SetWindowFontScale(float scale) // Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. ImVec2 ImGui::GetCursorPos() { - ImGuiWindow* window = GetCurrentWindow(); - return window->DC.CursorPos - window->Pos; + ImGuiWindow* window = GetCurrentWindowRead(); + 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); } ImVec2 ImGui::GetCursorStartPos() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.CursorStartPos - window->Pos; } ImVec2 ImGui::GetCursorScreenPos() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.CursorPos; } @@ -4677,23 +4743,40 @@ void ImGui::SetCursorScreenPos(const ImVec2& screen_pos) window->DC.CursorPos = screen_pos; } +float ImGui::GetScrollX() +{ + return GImGui->CurrentWindow->Scroll.x; +} + float ImGui::GetScrollY() { - ImGuiWindow* window = GetCurrentWindow(); - return window->ScrollY; + return GImGui->CurrentWindow->Scroll.y; +} + +float ImGui::GetScrollMaxX() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->SizeContents.x - window->SizeFull.x - window->ScrollbarSizes.x; } float ImGui::GetScrollMaxY() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->SizeContents.y - window->SizeFull.y - window->ScrollbarSizes.y; +} + +void ImGui::SetScrollX(float scroll_x) { ImGuiWindow* window = GetCurrentWindow(); - return window->SizeContents.y - window->SizeFull.y; + window->ScrollTarget.x = scroll_x; + window->ScrollTargetCenterRatio.x = 0.0f; } void ImGui::SetScrollY(float scroll_y) { ImGuiWindow* window = GetCurrentWindow(); - window->ScrollTargetRelY = scroll_y + window->TitleBarHeight(); // title bar height cancelled out when using ScrollTargetRelY - window->ScrollTargetCenterRatioY = 0.0f; + window->ScrollTarget.y = scroll_y + window->TitleBarHeight(); // title bar height canceled out when using ScrollTargetRelY + window->ScrollTargetCenterRatio.y = 0.0f; } void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio) @@ -4701,10 +4784,10 @@ void ImGui::SetScrollFromPosY(float pos_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 ImGuiWindow* window = GetCurrentWindow(); IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); - window->ScrollTargetRelY = (float)(int)(pos_y + window->ScrollY); - if (center_y_ratio <= 0.0f && window->ScrollTargetRelY <= window->WindowPadding.y) // Minor hack to make "scroll to top" take account of WindowPadding, else it would scroll to (WindowPadding.y - ItemSpacing.y) - window->ScrollTargetRelY = 0.0f; - window->ScrollTargetCenterRatioY = center_y_ratio; + window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y); + if (center_y_ratio <= 0.0f && window->ScrollTarget.y <= window->WindowPadding.y) // Minor hack to make "scroll to top" take account of WindowPadding, else it would scroll to (WindowPadding.y - ItemSpacing.y) + window->ScrollTarget.y = 0.0f; + window->ScrollTargetCenterRatio.y = center_y_ratio; } // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. @@ -4730,7 +4813,7 @@ void ImGui::SetStateStorage(ImGuiStorage* tree) ImGuiStorage* ImGui::GetStateStorage() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.StateStorage; } @@ -4896,7 +4979,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) text_pos.y += window->DC.CurrentLineTextBaseOffset; ImRect bb(text_pos, text_pos + text_size); - ItemSize(bb.GetSize()); + ItemSize(text_size); if (!ItemAdd(bb, NULL)) return; @@ -4926,7 +5009,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; - const float w = ImGui::CalcItemWidth(); + const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + style.FramePadding.x*2, label_size.y + style.FramePadding.y*2)); @@ -5199,9 +5282,9 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I void ImGui::LogToTTY(int max_depth) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); if (g.LogEnabled) return; + ImGuiWindow* window = GetCurrentWindowRead(); g.LogEnabled = true; g.LogFile = stdout; @@ -5214,9 +5297,10 @@ void ImGui::LogToTTY(int max_depth) void ImGui::LogToFile(int max_depth, const char* filename) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); if (g.LogEnabled) return; + ImGuiWindow* window = GetCurrentWindowRead(); + if (!filename) { filename = g.IO.LogFilename; @@ -5239,10 +5323,10 @@ void ImGui::LogToFile(int max_depth, const char* filename) // Start logging ImGui output to clipboard void ImGui::LogToClipboard(int max_depth) { - ImGuiWindow* window = GetCurrentWindow(); ImGuiState& g = *GImGui; if (g.LogEnabled) return; + ImGuiWindow* window = GetCurrentWindowRead(); g.LogEnabled = true; g.LogFile = NULL; @@ -5441,7 +5525,10 @@ void ImGui::Bullet() const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height, line_height)); ItemSize(bb); if (!ItemAdd(bb, NULL)) + { + ImGui::SameLine(0, -1); return; + } // Render const float bullet_size = line_height*0.15f; @@ -5916,7 +6003,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const float w = ImGui::CalcItemWidth(); + const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); @@ -6215,7 +6302,7 @@ bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, f ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const float w = ImGui::CalcItemWidth(); + const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); @@ -6425,7 +6512,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); if (graph_size.x == 0.0f) - graph_size.x = ImGui::CalcItemWidth() + (style.FramePadding.x * 2); + graph_size.x = CalcItemWidth() + (style.FramePadding.x * 2); if (graph_size.y == 0.0f) graph_size.y = label_size.y + (style.FramePadding.y * 2); @@ -6930,7 +7017,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); - ImVec2 size = CalcItemSize(size_arg, ImGui::CalcItemWidth(), is_multiline ? ImGui::GetTextLineHeight() * 8.0f : label_size.y); // Arbitrary default of 8 lines high for multi-line + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), is_multiline ? ImGui::GetTextLineHeight() * 8.0f : label_size.y); // Arbitrary default of 8 lines high for multi-line const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size + style.FramePadding*2.0f); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); @@ -6946,7 +7033,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 { @@ -7079,8 +7166,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_ctrl_only = is_ctrl_down && !is_alt_down && !is_shift_down; if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->ScrollY - g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); } - else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->ScrollY + g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y - g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); } + else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y + g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); } else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } @@ -7325,13 +7412,13 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Vertical scroll if (is_multiline) { - float scroll_y = draw_window->ScrollY; + float scroll_y = draw_window->Scroll.y; if (cursor_offset.y - g.FontSize < scroll_y) scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); else if (cursor_offset.y - size.y >= scroll_y) scroll_y = cursor_offset.y - size.y; - draw_window->DC.CursorPos.y += (draw_window->ScrollY - scroll_y); // To avoid a frame of lag - draw_window->ScrollY = scroll_y; + draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // To avoid a frame of lag + draw_window->Scroll.y = scroll_y; render_pos.y = draw_window->DC.CursorPos.y; } } @@ -7437,7 +7524,7 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; - const float w = ImGui::CalcItemWidth(); + const float w = CalcItemWidth(); const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); @@ -7652,7 +7739,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const float w = ImGui::CalcItemWidth(); + const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f); @@ -7844,7 +7931,7 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. - ImVec2 size = CalcItemSize(size_arg, ImGui::CalcItemWidth() + style.FramePadding.x * 2.0f, ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth() + style.FramePadding.x * 2.0f, ImGui::GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); @@ -8189,7 +8276,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const float w_full = ImGui::CalcItemWidth(); + const float w_full = CalcItemWidth(); const float square_sz = (g.FontSize + style.FramePadding.y * 2.0f); ImGuiColorEditMode edit_mode = window->DC.ColorEditMode; @@ -8333,7 +8420,7 @@ void ImGui::Separator() x1 += window->DC.ColumnsStartX; const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y)); - ItemSize(ImVec2(0.0f, bb.GetSize().y)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit + ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit // FIXME: Height should be 1.0f not 0.0f ? if (!ItemAdd(bb, NULL)) { if (window->DC.ColumnsCount > 1) @@ -8372,7 +8459,7 @@ void ImGui::Dummy(const ImVec2& size) bool ImGui::IsRectVisible(const ImVec2& size) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); } @@ -8444,7 +8531,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 @@ -8495,13 +8582,13 @@ void ImGui::NextColumn() int ImGui::GetColumnIndex() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.ColumnsCurrent; } int ImGui::GetColumnsCount() { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); return window->DC.ColumnsCount; } @@ -8510,7 +8597,7 @@ static float GetDraggedColumnOffset(int column_index) // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing // window creates a feedback loop because we store normalized positions/ So while dragging we enforce absolute positioning ImGuiState& g = *GImGui; - ImGuiWindow* window = ImGui::GetCurrentWindow(); + ImGuiWindow* window = ImGui::GetCurrentWindowRead(); IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets. IM_ASSERT(g.ActiveId == window->DC.ColumnsSetID + ImGuiID(column_index)); @@ -8523,7 +8610,7 @@ static float GetDraggedColumnOffset(int column_index) float ImGui::GetColumnOffset(int column_index) { ImGuiState& g = *GImGui; - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); if (column_index < 0) column_index = window->DC.ColumnsCurrent; @@ -8538,8 +8625,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 content_region_width = window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x; const float min_x = window->DC.ColumnsStartX; - const float max_x = window->Size.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarWidth);// - window->WindowPadding().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; } @@ -8554,8 +8642,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 content_region_width = window->SizeContentsExplicit.x ? window->SizeContentsExplicit.x : window->Size.x; const float min_x = window->DC.ColumnsStartX; - const float max_x = window->Size.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarWidth);// - window->WindowPadding().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; @@ -8563,7 +8652,7 @@ void ImGui::SetColumnOffset(int column_index, float offset) float ImGui::GetColumnWidth(int column_index) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiWindow* window = GetCurrentWindowRead(); if (column_index < 0) column_index = window->DC.ColumnsCurrent; diff --git a/3rdparty/ocornut-imgui/imgui.h b/3rdparty/ocornut-imgui/imgui.h index f71d0e201..3b0f79f57 100644 --- a/3rdparty/ocornut-imgui/imgui.h +++ b/3rdparty/ocornut-imgui/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.45 WIP +// ImGui library v1.45 // Headers // See imgui.cpp file for documentation. @@ -17,7 +17,7 @@ #include // NULL, malloc, free, qsort, atoi #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.45 WIP" +#define IMGUI_VERSION "1.45" // Define assertion handler. #ifndef IM_ASSERT @@ -120,10 +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 @@ -136,7 +138,9 @@ 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 to ImVec2(0,0) to force an auto-fit. 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 @@ -144,12 +148,15 @@ namespace ImGui IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set current window collapsed state IMGUI_API void SetWindowFocus(); // set current window to be focused / front-most IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond = 0); // set named window position - call within Begin()/End(). may incur tearing - IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. may incur tearing IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus. + IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()] IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()] - IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount == ContentSize.Y - WindowSize.Y + IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.X - WindowSize.X + IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y + IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()] IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()] IMGUI_API void SetScrollHere(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions. @@ -174,7 +181,7 @@ namespace ImGui IMGUI_API void PopAllowKeyboardFocus(); IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space IMGUI_API void PopTextWrapPos(); - IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return true multiple times as you hold them (uses io.KeyRepeatDelay/io.KeyRepeatRate for now) + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (uses io.KeyRepeatDelay/io.KeyRepeatRate for now). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. IMGUI_API void PopButtonRepeat(); // Cursor / Layout @@ -448,6 +455,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() @@ -639,7 +647,7 @@ struct ImGuiStyle float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin() float IndentSpacing; // Horizontal indentation when e.g. entering a tree node float ColumnsMinSpacing; // Minimum horizontal spacing between two columns - float ScrollbarWidth; // Width of the vertical scrollbar + float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar float ScrollbarRounding; // Radius of grab corners for scrollbar float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. @@ -1108,10 +1116,10 @@ struct ImDrawList inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || _Path[_Path.Size-1].x != pos.x || _Path[_Path.Size-1].y != pos.y) _Path.push_back(pos); } inline void PathFill(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col, true); PathClear(); } - inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness, true); PathClear(); } - IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); + inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness, true); PathClear(); } + IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle - IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); + IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners = 0x0F); // Channels diff --git a/3rdparty/ocornut-imgui/imgui_demo.cpp b/3rdparty/ocornut-imgui/imgui_demo.cpp index 48be4a7aa..3f6f90e2c 100644 --- a/3rdparty/ocornut-imgui/imgui_demo.cpp +++ b/3rdparty/ocornut-imgui/imgui_demo.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.45 WIP +// ImGui library v1.45 // Demo code // Don't remove this file from your project! It is useful reference code that you can execute. @@ -701,7 +701,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::PushItemWidth(100); goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); ImGui::PopItemWidth(); - ImGui::BeginChild("Sub1", ImVec2(ImGui::GetWindowWidth() * 0.5f,300)); + ImGui::BeginChild("Sub1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f,300), false, ImGuiWindowFlags_HorizontalScrollbar); for (int i = 0; i < 100; i++) { ImGui::Text("%04d: scrollable region", i); @@ -735,19 +735,24 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::TreeNode("Widgets Alignment")) { static float f = 0.0f; - ImGui::Text("Fixed: 100 pixels"); + ImGui::Text("PushItemWidth(100)"); ImGui::PushItemWidth(100); - ImGui::InputFloat("float##1", &f); + ImGui::DragFloat("float##1", &f); ImGui::PopItemWidth(); - ImGui::Text("Proportional: 50%% of window width"); + ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f);"); ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f); - ImGui::InputFloat("float##2", &f); + ImGui::DragFloat("float##2", &f); ImGui::PopItemWidth(); - ImGui::Text("Right-aligned: Leave 100 pixels for label"); + ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f);"); + ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f); + ImGui::DragFloat("float##3", &f); + ImGui::PopItemWidth(); + + ImGui::Text("PushItemWidth(-100);"); ImGui::PushItemWidth(-100); - ImGui::InputFloat("float##3", &f); + ImGui::DragFloat("float##4", &f); ImGui::PopItemWidth(); ImGui::TreePop(); @@ -907,7 +912,7 @@ void ImGui::ShowTestWindow(bool* opened) static bool track = true; static int track_line = 50, scroll_to_px = 200; ImGui::Checkbox("Track", &track); - ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 9999, "Line %.0f"); + ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line %.0f"); bool scroll_to = ImGui::Button("Scroll To"); ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "y = %.0f px"); if (scroll_to) track = false; @@ -938,6 +943,47 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TreePop(); } + if (ImGui::TreeNode("Horizontal Scrolling")) + { + ImGui::Bullet(); ImGui::TextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag."); + ImGui::Bullet(); ImGui::TextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin()."); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); + ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetItemsLineHeightWithSpacing()*7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar); + for (int line = 0; line < 7; line++) + { + // Display random stuff + int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); + for (int n = 0; n < num_buttons; n++) + { + if (n > 0) ImGui::SameLine(); + ImGui::PushID(n + line * 1000); + char num_buf[16]; + const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : (sprintf(num_buf, "%d", n), num_buf); + float hue = n*0.05f; + ImGui::PushStyleColor(ImGuiCol_Button, ImColor::HSV(hue, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImColor::HSV(hue, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImColor::HSV(hue, 0.8f, 0.8f)); + ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + } + ImGui::EndChild(); + ImGui::PopStyleVar(2); + float scroll_x_delta = 0.0f; + ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; + ImGui::SameLine(); ImGui::Text("Scroll from code"); ImGui::SameLine(); + ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; + if (scroll_x_delta != 0.0f) + { + ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window) + ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); + ImGui::End(); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Clipping")) { static ImVec2 size(100, 100), offset(50, 20); @@ -1205,7 +1251,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Separator(); ImGui::Spacing(); - // Word-wrapping + // Word wrapping ImGui::Text("Word-wrapping:"); ImGui::Columns(2, "word-wrapping"); ImGui::Separator(); @@ -1411,7 +1457,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); - ImGui::SliderFloat("ScrollbarWidth", &style.ScrollbarWidth, 1.0f, 20.0f, "%.0f"); + ImGui::SliderFloat("ScrollbarWidth", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 16.0f, "%.0f"); @@ -1757,7 +1803,7 @@ struct ExampleAppConsole // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); // NB- if you have thousands of entries this approach may be too inefficient. You can seek and display only the lines that are visible - CalcListClipping() is a helper to compute this information. // If your items are of variable size you may want to implement code similar to what CalcListClipping() does. Or split your data into fixed height items to allow random-seeking into your list. - ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetItemsLineHeightWithSpacing())); + ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetItemsLineHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar); if (ImGui::BeginPopupContextWindow()) { if (ImGui::Selectable("Clear")) ClearLog(); @@ -1989,7 +2035,7 @@ struct ExampleAppLog ImGui::SameLine(); Filter.Draw("Filter", -100.0f); ImGui::Separator(); - ImGui::BeginChild("scrolling"); + ImGui::BeginChild("scrolling", ImVec2(0,0), false, ImGuiWindowFlags_HorizontalScrollbar); if (copy) ImGui::LogToClipboard(); if (Filter.IsActive()) @@ -2110,16 +2156,16 @@ static void ShowExampleAppLongText(bool* opened) ImGui::TextUnformatted(log.begin(), log.end()); break; case 1: - // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the CalcListClipping() helper. - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); - int display_start, display_end; - ImGui::CalcListClipping(lines, ImGui::GetTextLineHeight(), &display_start, &display_end); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (display_start) * ImGui::GetTextLineHeight()); - for (int i = display_start; i < display_end; i++) - ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (lines - display_end) * ImGui::GetTextLineHeight()); - ImGui::PopStyleVar(); - break; + { + // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); + ImGuiListClipper clipper(lines, ImGui::GetTextLineHeight()); + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog\n", i); + clipper.End(); + ImGui::PopStyleVar(); + break; + } case 2: // Multiple calls to Text(), not clipped (slow) ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,0)); diff --git a/3rdparty/ocornut-imgui/imgui_draw.cpp b/3rdparty/ocornut-imgui/imgui_draw.cpp index e1a3ea85a..0b9a918f0 100644 --- a/3rdparty/ocornut-imgui/imgui_draw.cpp +++ b/3rdparty/ocornut-imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.45 WIP +// ImGui library v1.45 // Drawing and font code // Contains implementation for @@ -1372,6 +1372,7 @@ void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects) ImVector& rects = *(ImVector*)p_rects; if (pass == 0) { + // Request rectangles stbrp_rect r; memset(&r, 0, sizeof(r)); r.w = (TEX_DATA_W*2)+1; @@ -1380,7 +1381,7 @@ void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects) } else if (pass == 1) { - // Copy pixels + // Render/copy pixels const stbrp_rect& r = rects[0]; for (int y = 0, n = 0; y < TEX_DATA_H; y++) for (int x = 0; x < TEX_DATA_W; x++, n++) diff --git a/3rdparty/ocornut-imgui/imgui_internal.h b/3rdparty/ocornut-imgui/imgui_internal.h index 7d45ec955..a154a9ea3 100644 --- a/3rdparty/ocornut-imgui/imgui_internal.h +++ b/3rdparty/ocornut-imgui/imgui_internal.h @@ -1,4 +1,4 @@ -// ImGui library v1.45 WIP +// ImGui library v1.45 // Internals // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! @@ -129,6 +129,7 @@ static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; } +static inline ImVec2 ImRound(ImVec2 v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } //----------------------------------------------------------------------------- // Types @@ -359,9 +360,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 +387,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 +449,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 +561,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") - float ScrollY; - 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; + ImVec2 Scroll; + ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) + ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered + 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 +619,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.ScrollbarWidth : 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); } }; @@ -626,7 +630,8 @@ public: namespace ImGui { - IMGUI_API ImGuiWindow* GetCurrentWindow(); + inline ImGuiWindow* GetCurrentWindowRead() { ImGuiState& g = *GImGui; return g.CurrentWindow; } // If this ever crash it means that ImGui::NewFrame() has never been called (which is illegal). We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) + inline ImGuiWindow* GetCurrentWindow() { ImGuiState& g = *GImGui; g.CurrentWindow->Accessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* GetParentWindow(); IMGUI_API void FocusWindow(ImGuiWindow* window);