mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 05:01:05 +01:00 
			
		
		
		
	Window rectangles: Changed WorkRect to cover the whole region including scrolling (toward obsolete ContentsRegionRect) + using full WindowPadding*1 padding.
Tweaked InnerClipRect. TreeNode, CollapsingHeader: Fixed highlight frame not covering horizontal area fully when using horizontal scrolling. (#2211, #2579) TabBar: Fixed BeginTabBar() within a window with horizontal scrolling from creating a feedback loop with the horizontal contents size. Columns: Fixed Columns() within a window with horizontal scrolling from not covering the full horizontal area (previously only worked with an explicit contents size). (#125) Demo: Added demo code to test contentsrect/workrect
This commit is contained in:
		| @@ -64,6 +64,12 @@ Other Changes: | ||||
|   frame as clearing the focus. This was in most noticeable in back-ends such as Glfw and SDL which | ||||
|   emits key release events when focusing another viewport, leading to Alt+clicking on void on another | ||||
|   viewport triggering the issue. (#2609) | ||||
| - TreeNode, CollapsingHeader: Fixed highlight frame not covering horizontal area fully when using | ||||
|   horizontal scrolling. (#2211, #2579) | ||||
| - TabBar: Fixed BeginTabBar() within a window with horizontal scrolling from creating a feedback | ||||
|   loop with the horizontal contents size. | ||||
| - Columns: Fixed Columns() within a window with horizontal scrolling from not covering the full | ||||
|   horizontal area (previously only worked with an explicit contents size). (#125) | ||||
| - Style: Added style.WindowMenuButtonPosition (left/right, defaults to ImGuiDir_Left) to move the | ||||
|   collapsing/docking button to the other side of the title bar. | ||||
| - Style: Made window close button cross slightly smaller. | ||||
|   | ||||
							
								
								
									
										44
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -4999,8 +4999,6 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Draw background and borders | ||||
| // Draw and handle scrollbars | ||||
| void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
| @@ -5511,7 +5509,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | ||||
|         // - Begin() initial clipping rect for drawing window background and borders. | ||||
|         // - Begin() clipping whole child | ||||
|         ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; | ||||
|         window->OuterRectClipped = window->Rect(); | ||||
|         ImRect outer_rect = window->Rect(); | ||||
|         window->OuterRectClipped = outer_rect; | ||||
|         window->OuterRectClipped.ClipWith(host_rect); | ||||
|  | ||||
|         // Inner rectangle | ||||
| @@ -5525,15 +5524,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | ||||
|         window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; | ||||
|         window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; | ||||
|  | ||||
|         // Work rectangle. | ||||
|         // Affected by window padding and border size. Used by: | ||||
|         // - Columns() for right-most edge | ||||
|         // - BeginTabBar() for right-most edge | ||||
|         window->WorkRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); | ||||
|         window->WorkRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y); | ||||
|         window->WorkRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); | ||||
|         window->WorkRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y); | ||||
|  | ||||
|         // Inner clipping rectangle. | ||||
|         // Will extend a little bit outside the normal work region. | ||||
|         // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. | ||||
| @@ -5541,7 +5531,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | ||||
|         // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. | ||||
|         // Affected by window/frame border size. Used by: | ||||
|         // - Begin() initial clip rect | ||||
|         window->InnerClipRect = window->WorkRect; | ||||
|         float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); | ||||
|         window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); | ||||
|         window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); | ||||
|         window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.y * 0.5f), window->WindowBorderSize)); | ||||
|         window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); | ||||
|         window->InnerClipRect.ClipWithFull(host_rect); | ||||
|  | ||||
|         // DRAWING | ||||
| @@ -5589,12 +5583,25 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | ||||
|  | ||||
|         // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) | ||||
|  | ||||
|         // Work rectangle. | ||||
|         // Affected by window padding and border size. Used by: | ||||
|         // - Columns() for right-most edge | ||||
|         // - TreeNode(), CollapsingHeader() for right-most edge | ||||
|         // - BeginTabBar() for right-most edge | ||||
|         const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); | ||||
|         const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); | ||||
|         const float work_rect_size_x = (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : ImMax(allow_scrollbar_x ? window->SizeContents.x : 0.0f, window->InnerRect.GetWidth() - window->WindowPadding.x * 2.0f)); | ||||
|         const float work_rect_size_y = (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : ImMax(allow_scrollbar_y ? window->SizeContents.y : 0.0f, window->InnerRect.GetHeight() - window->WindowPadding.y * 2.0f)); | ||||
|         window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); | ||||
|         window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); | ||||
|         window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; | ||||
|         window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; | ||||
|  | ||||
|         // [LEGACY] Contents Region | ||||
|         // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. | ||||
|         // FIXME-OBSOLETE: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. | ||||
|         // NB: WindowBorderSize is included in WindowPadding _and_ ScrollbarSizes so we need to cancel one out when we have both. | ||||
|         // Used by: | ||||
|         // - Mouse wheel scrolling | ||||
|         // - ... (many things) | ||||
|         // - Mouse wheel scrolling + many other things | ||||
|         window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x; | ||||
|         window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight(); | ||||
|         window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x + ImMin(window->ScrollbarSizes.x, window->WindowBorderSize))); | ||||
| @@ -8719,9 +8726,8 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag | ||||
|     window->DC.CurrentColumns = columns; | ||||
|  | ||||
|     // Set state for first column | ||||
|     const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->WorkRect.Max.x - window->Pos.x); | ||||
|     columns->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range | ||||
|     columns->OffMaxX = ImMax(content_region_width - window->Scroll.x, columns->OffMinX + 1.0f); | ||||
|     columns->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x; | ||||
|     columns->OffMaxX = ImMax(window->WorkRect.Max.x - window->Pos.x, columns->OffMinX + 1.0f); | ||||
|     columns->HostCursorPosY = window->DC.CursorPos.y; | ||||
|     columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; | ||||
|     columns->HostClipRect = window->ClipRect; | ||||
|   | ||||
| @@ -17,9 +17,18 @@ | ||||
| // In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is | ||||
| // essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data | ||||
| // in the same place, to make the demo source code faster to read, faster to write, and smaller in size. | ||||
| // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant | ||||
| // or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is | ||||
| // likely going to be stored outside your functions. | ||||
| // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be  | ||||
| // reentrant or used in multiple threads. This might be a pattern you will want to use in your code, but most of the real data | ||||
| // you would be editing is likely going to be stored outside your functions. | ||||
|  | ||||
| // The Demo code is this file is designed to be easy to copy-and-paste in into your application! | ||||
| // Because of this: | ||||
| // - We never omit the ImGui:: namespace when calling functions, even though most of our code is already in the same namespace. | ||||
| // - We try to declare static variables in the local scope, as close as possible to the code using them. | ||||
| // - We never use any of the helpers/facilities used internally by dear imgui, unless it has been exposed in the public API (imgui.h). | ||||
| // - We never use maths operators on ImVec2/ImVec4. For other imgui sources files, they are provided by imgui_internal.h w/ IMGUI_DEFINE_MATH_OPERATORS, | ||||
| //   for your own sources file they are optional and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h. | ||||
| //   Because we don't want to assume anything about your support of maths operators, we don't use them in imgui_demo.cpp. | ||||
|  | ||||
| /* | ||||
|  | ||||
| @@ -2135,6 +2144,83 @@ static void ShowDemoWindowLayout() | ||||
|             ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); | ||||
|             ImGui::EndChild(); | ||||
|         } | ||||
|         ImGui::Spacing(); | ||||
|  | ||||
|         static bool show_horizontal_contents_size_demo_window = false; | ||||
|         ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window); | ||||
|  | ||||
|         if (show_horizontal_contents_size_demo_window) | ||||
|         { | ||||
|             static bool show_h_scrollbar = true; | ||||
|             static bool show_button = true; | ||||
|             static bool show_tree_nodes = true; | ||||
|             static bool show_columns = true; | ||||
|             static bool show_tab_bar = true; | ||||
|             static bool explicit_content_size = false; | ||||
|             static float contents_size_x = 300.0f; | ||||
|             if (explicit_content_size) | ||||
|                 ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); | ||||
|             ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); | ||||
|             ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); | ||||
|             ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); | ||||
|             HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); | ||||
|             ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); | ||||
|             ImGui::Checkbox("Button", &show_button);            // Will grow contents size (unless explicitly overwritten) | ||||
|             ImGui::Checkbox("Tree nodes", &show_tree_nodes);    // Will grow contents size and display highlight over full width | ||||
|             ImGui::Checkbox("Columns", &show_columns);          // Will use contents size | ||||
|             ImGui::Checkbox("Tab bar", &show_tab_bar);          // Will use contents size | ||||
|             ImGui::Checkbox("Explicit content size", &explicit_content_size); | ||||
|             if (explicit_content_size) | ||||
|             { | ||||
|                 ImGui::SameLine(); | ||||
|                 ImGui::SetNextItemWidth(100); | ||||
|                 ImGui::DragFloat("##csx", &contents_size_x); | ||||
|                 ImVec2 p = ImGui::GetCursorScreenPos();  | ||||
|                 ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); | ||||
|                 ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); | ||||
|                 ImGui::Dummy(ImVec2(0, 10)); | ||||
|             } | ||||
|             ImGui::PopStyleVar(2); | ||||
|             ImGui::Separator(); | ||||
|             if (show_button) | ||||
|             { | ||||
|                 ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); | ||||
|             } | ||||
|             if (show_tree_nodes) | ||||
|             { | ||||
|                 bool open = true; | ||||
|                 if (ImGui::TreeNode("this is a tree node")) | ||||
|                 { | ||||
|                     if (ImGui::TreeNode("another one of those tree node...")) | ||||
|                     { | ||||
|                         ImGui::Text("Some tree contents"); | ||||
|                         ImGui::TreePop(); | ||||
|                     } | ||||
|                     ImGui::TreePop(); | ||||
|                 } | ||||
|                 ImGui::CollapsingHeader("CollapsingHeader", &open); | ||||
|             } | ||||
|             if (show_columns) | ||||
|             { | ||||
|                 ImGui::Columns(4); | ||||
|                 for (int n = 0; n < 4; n++) | ||||
|                 { | ||||
|                     ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); | ||||
|                     ImGui::NextColumn(); | ||||
|                 } | ||||
|                 ImGui::Columns(1); | ||||
|             } | ||||
|             if (show_tab_bar && ImGui::BeginTabBar("Hello")) | ||||
|             { | ||||
|                 if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } | ||||
|                 if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } | ||||
|                 if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } | ||||
|                 if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } | ||||
|                 ImGui::EndTabBar(); | ||||
|             } | ||||
|             ImGui::End(); | ||||
|         } | ||||
|  | ||||
|         ImGui::TreePop(); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1294,12 +1294,16 @@ struct IMGUI_API ImGuiWindow | ||||
|  | ||||
|     ImGuiWindowTempData     DC;                                 // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. | ||||
|     ImVector<ImGuiID>       IDStack;                            // ID stack. ID are hashes seeded with the value at the top of the stack | ||||
|     ImRect                  ClipRect;                           // Current clipping rectangle. = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. | ||||
|     ImRect                  OuterRectClipped;                   // == WindowRect just after setup in Begin(). == window->Rect() for root window. | ||||
|     ImRect                  InnerRect;                          // Inner rectangle | ||||
|     ImRect                  InnerClipRect;                      // == InnerRect minus WindowPadding.x, clipped within viewport or parent clip rect. | ||||
|     ImRect                  WorkRect;                           // == InnerRect minus WindowPadding.x | ||||
|     ImRect                  ContentsRegionRect;                 // FIXME: This is currently confusing/misleading. Maximum visible content position ~~ Pos + (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis | ||||
|  | ||||
|     // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer. | ||||
|     // The main 'OuterRect', omitted as a field, is window->Rect(). | ||||
|     ImRect                  OuterRectClipped;                   // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. | ||||
|     ImRect                  InnerRect;                          // Inner rectangle (omit title bar, menu bar) | ||||
|     ImRect                  InnerClipRect;                      // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. | ||||
|     ImRect                  WorkRect;                           // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentsRegionRect over time (from 1.71+ onward). | ||||
|     ImRect                  ClipRect;                           // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). | ||||
|     ImRect                  ContentsRegionRect;                 // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. | ||||
|  | ||||
|     int                     LastFrameActive;                    // Last frame number the window was Active. | ||||
|     float                   ItemWidthDefault; | ||||
|     ImGuiMenuColumns        MenuColumns;                        // Simplified columns storage for menu items | ||||
|   | ||||
| @@ -5127,12 +5127,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l | ||||
|     // We vertically grow up to current line height up the typical widget height. | ||||
|     const float text_base_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it | ||||
|     const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); | ||||
|     ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetContentRegionMaxAbs().x, window->DC.CursorPos.y + frame_height)); | ||||
|     ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->WorkRect.Max.x, window->DC.CursorPos.y + frame_height)); | ||||
|     if (display_frame) | ||||
|     { | ||||
|         // Framed header expand a little outside the default padding | ||||
|         frame_bb.Min.x -= (float)(int)(window->WindowPadding.x * 0.5f) - 1; | ||||
|         frame_bb.Max.x += (float)(int)(window->WindowPadding.x * 0.5f) - 1; | ||||
|         frame_bb.Min.x -= (float)(int)(window->WindowPadding.x * 0.5f - 1.0f); | ||||
|         frame_bb.Max.x += (float)(int)(window->WindowPadding.x * 0.5f - 1.0f); | ||||
|     } | ||||
|  | ||||
|     const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2));   // Collapser arrow width + Spacing | ||||
| @@ -6324,15 +6324,15 @@ bool    ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG | ||||
|     tab_bar->FramePadding = g.Style.FramePadding; | ||||
|  | ||||
|     // Layout | ||||
|     ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight())); | ||||
|     ItemSize(ImVec2(0.0f /*tab_bar->OffsetMax*/, tab_bar->BarRect.GetHeight())); // Don't feed width back | ||||
|     window->DC.CursorPos.x = tab_bar->BarRect.Min.x; | ||||
|  | ||||
|     // Draw separator | ||||
|     const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab); | ||||
|     const float y = tab_bar->BarRect.Max.y - 1.0f; | ||||
|     { | ||||
|         const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x; | ||||
|         const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x; | ||||
|         const float separator_min_x = tab_bar->BarRect.Min.x - ImFloor(window->WindowPadding.x * 0.5f); | ||||
|         const float separator_max_x = tab_bar->BarRect.Max.x + ImFloor(window->WindowPadding.x * 0.5f); | ||||
|         window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); | ||||
|     } | ||||
|     return true; | ||||
| @@ -6874,7 +6874,10 @@ bool    ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, | ||||
|     if (want_clip_rect) | ||||
|         PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true); | ||||
|  | ||||
|     ItemSize(bb, style.FramePadding.y); | ||||
|     ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; | ||||
|     ItemSize(bb.GetSize(), style.FramePadding.y); | ||||
|     window->DC.CursorMaxPos = backup_cursor_max_pos; | ||||
|  | ||||
|     if (!ItemAdd(bb, id)) | ||||
|     { | ||||
|         if (want_clip_rect) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user