diff --git a/imgui.cpp b/imgui.cpp index 779ea09..a75829e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1140,7 +1140,7 @@ ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 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 @@ -5452,6 +5452,7 @@ window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; @@ -8434,12 +8435,12 @@ static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm) { - return offset_norm * (columns->MaxX - columns->MinX); + return offset_norm * (columns->OffMaxX - columns->OffMinX); } static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset) { - return offset / (columns->MaxX - columns->MinX); + return offset / (columns->OffMaxX - columns->OffMinX); } static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; @@ -8472,7 +8473,7 @@ IM_ASSERT(column_index < columns->Columns.Size); const float t = columns->Columns[column_index].OffsetNorm; - const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); return x_offset; } @@ -8515,8 +8516,8 @@ const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) - offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); - columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX); if (preserve_width) SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); @@ -8551,7 +8552,7 @@ ImGuiColumns* columns = window->DC.CurrentColumns; window->DrawList->ChannelsSetCurrent(0); int cmd_size = window->DrawList->CmdBuffer.Size; - PushClipRect(columns->BackupClipRect.Min, columns->BackupClipRect.Max, false); + PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd } @@ -8597,9 +8598,8 @@ IM_ASSERT(columns_count >= 1); IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported - ImGuiID id = GetColumnsID(str_id, columns_count); - // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); ImGuiColumns* columns = FindOrCreateColumns(window, id); IM_ASSERT(columns->ID == id); columns->Current = 0; @@ -8609,11 +8609,11 @@ // Set state for first column const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); - columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range - columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); - columns->BackupCursorPosY = window->DC.CursorPos.y; - columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x; - columns->BackupClipRect = window->ClipRect; + 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->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostClipRect = window->ClipRect; columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -8622,7 +8622,7 @@ if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) columns->Columns.resize(0); - // Initialize defaults + // Initialize default widths columns->IsFirstFrame = (columns->Columns.Size == 0); if (columns->Columns.Size == 0) { @@ -8668,17 +8668,19 @@ window->DrawList->ChannelsMerge(); } + const ImGuiColumnsFlags flags = columns->Flags; columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); window->DC.CursorPos.y = columns->LineMaxY; - if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) - window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy bool is_being_resized = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) + if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) { // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. - const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y); + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); int dragging_column = -1; for (int n = 1; n < columns->Count; n++) @@ -8693,7 +8695,7 @@ continue; bool hovered = false, held = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) + if (!(flags & ImGuiColumnsFlags_NoResize)) { ButtonBehavior(column_hit_rect, column_id, &hovered, &held); if (hovered || held) @@ -8745,6 +8747,7 @@ BeginColumns(id, columns_count, flags); } + //----------------------------------------------------------------------------- // [SECTION] DRAG AND DROP //----------------------------------------------------------------------------- @@ -9692,7 +9695,7 @@ { if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) return; - ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); for (int column_n = 0; column_n < columns->Columns.Size; column_n++) ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); ImGui::TreePop(); diff --git a/imgui.cpp b/imgui.cpp index 779ea09..a75829e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1140,7 +1140,7 @@ ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 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 @@ -5452,6 +5452,7 @@ window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; @@ -8434,12 +8435,12 @@ static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm) { - return offset_norm * (columns->MaxX - columns->MinX); + return offset_norm * (columns->OffMaxX - columns->OffMinX); } static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset) { - return offset / (columns->MaxX - columns->MinX); + return offset / (columns->OffMaxX - columns->OffMinX); } static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; @@ -8472,7 +8473,7 @@ IM_ASSERT(column_index < columns->Columns.Size); const float t = columns->Columns[column_index].OffsetNorm; - const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); return x_offset; } @@ -8515,8 +8516,8 @@ const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) - offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); - columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX); if (preserve_width) SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); @@ -8551,7 +8552,7 @@ ImGuiColumns* columns = window->DC.CurrentColumns; window->DrawList->ChannelsSetCurrent(0); int cmd_size = window->DrawList->CmdBuffer.Size; - PushClipRect(columns->BackupClipRect.Min, columns->BackupClipRect.Max, false); + PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd } @@ -8597,9 +8598,8 @@ IM_ASSERT(columns_count >= 1); IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported - ImGuiID id = GetColumnsID(str_id, columns_count); - // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); ImGuiColumns* columns = FindOrCreateColumns(window, id); IM_ASSERT(columns->ID == id); columns->Current = 0; @@ -8609,11 +8609,11 @@ // Set state for first column const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); - columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range - columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); - columns->BackupCursorPosY = window->DC.CursorPos.y; - columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x; - columns->BackupClipRect = window->ClipRect; + 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->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostClipRect = window->ClipRect; columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -8622,7 +8622,7 @@ if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) columns->Columns.resize(0); - // Initialize defaults + // Initialize default widths columns->IsFirstFrame = (columns->Columns.Size == 0); if (columns->Columns.Size == 0) { @@ -8668,17 +8668,19 @@ window->DrawList->ChannelsMerge(); } + const ImGuiColumnsFlags flags = columns->Flags; columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); window->DC.CursorPos.y = columns->LineMaxY; - if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) - window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy bool is_being_resized = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) + if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) { // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. - const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y); + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); int dragging_column = -1; for (int n = 1; n < columns->Count; n++) @@ -8693,7 +8695,7 @@ continue; bool hovered = false, held = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) + if (!(flags & ImGuiColumnsFlags_NoResize)) { ButtonBehavior(column_hit_rect, column_id, &hovered, &held); if (hovered || held) @@ -8745,6 +8747,7 @@ BeginColumns(id, columns_count, flags); } + //----------------------------------------------------------------------------- // [SECTION] DRAG AND DROP //----------------------------------------------------------------------------- @@ -9692,7 +9695,7 @@ { if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) return; - ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); for (int column_n = 0; column_n < columns->Columns.Size; column_n++) ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); ImGui::TreePop(); diff --git a/imgui.h b/imgui.h index aafcb3a..0d46ec5 100644 --- a/imgui.h +++ b/imgui.h @@ -1293,7 +1293,7 @@ ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 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. diff --git a/imgui.cpp b/imgui.cpp index 779ea09..a75829e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1140,7 +1140,7 @@ ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 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 @@ -5452,6 +5452,7 @@ window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; @@ -8434,12 +8435,12 @@ static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm) { - return offset_norm * (columns->MaxX - columns->MinX); + return offset_norm * (columns->OffMaxX - columns->OffMinX); } static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset) { - return offset / (columns->MaxX - columns->MinX); + return offset / (columns->OffMaxX - columns->OffMinX); } static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; @@ -8472,7 +8473,7 @@ IM_ASSERT(column_index < columns->Columns.Size); const float t = columns->Columns[column_index].OffsetNorm; - const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); return x_offset; } @@ -8515,8 +8516,8 @@ const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) - offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); - columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX); if (preserve_width) SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); @@ -8551,7 +8552,7 @@ ImGuiColumns* columns = window->DC.CurrentColumns; window->DrawList->ChannelsSetCurrent(0); int cmd_size = window->DrawList->CmdBuffer.Size; - PushClipRect(columns->BackupClipRect.Min, columns->BackupClipRect.Max, false); + PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd } @@ -8597,9 +8598,8 @@ IM_ASSERT(columns_count >= 1); IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported - ImGuiID id = GetColumnsID(str_id, columns_count); - // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); ImGuiColumns* columns = FindOrCreateColumns(window, id); IM_ASSERT(columns->ID == id); columns->Current = 0; @@ -8609,11 +8609,11 @@ // Set state for first column const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); - columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range - columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); - columns->BackupCursorPosY = window->DC.CursorPos.y; - columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x; - columns->BackupClipRect = window->ClipRect; + 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->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostClipRect = window->ClipRect; columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -8622,7 +8622,7 @@ if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) columns->Columns.resize(0); - // Initialize defaults + // Initialize default widths columns->IsFirstFrame = (columns->Columns.Size == 0); if (columns->Columns.Size == 0) { @@ -8668,17 +8668,19 @@ window->DrawList->ChannelsMerge(); } + const ImGuiColumnsFlags flags = columns->Flags; columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); window->DC.CursorPos.y = columns->LineMaxY; - if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) - window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy bool is_being_resized = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) + if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) { // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. - const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y); + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); int dragging_column = -1; for (int n = 1; n < columns->Count; n++) @@ -8693,7 +8695,7 @@ continue; bool hovered = false, held = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) + if (!(flags & ImGuiColumnsFlags_NoResize)) { ButtonBehavior(column_hit_rect, column_id, &hovered, &held); if (hovered || held) @@ -8745,6 +8747,7 @@ BeginColumns(id, columns_count, flags); } + //----------------------------------------------------------------------------- // [SECTION] DRAG AND DROP //----------------------------------------------------------------------------- @@ -9692,7 +9695,7 @@ { if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) return; - ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); for (int column_n = 0; column_n < columns->Columns.Size; column_n++) ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); ImGui::TreePop(); diff --git a/imgui.h b/imgui.h index aafcb3a..0d46ec5 100644 --- a/imgui.h +++ b/imgui.h @@ -1293,7 +1293,7 @@ ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 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. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1f01cc4..e0d9c76 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2426,6 +2426,32 @@ ImGui::TreePop(); } + if (ImGui::TreeNode("Borders")) + { + // NB: Future columns API should allow automatic horizontal borders. + static bool h_borders = true; + static bool v_borders = true; + ImGui::Checkbox("horizontal", &h_borders); + ImGui::SameLine(); + ImGui::Checkbox("vertical", &v_borders); + ImGui::Columns(4, NULL, v_borders); + for (int i = 0; i < 4 * 3; i++) + { + if (h_borders && ImGui::GetColumnIndex() == 0) + ImGui::Separator(); + ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); + ImGui::Text("Long text that is likely to clip"); + ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); + ImGui::NextColumn(); + } + ImGui::Columns(1); + if (h_borders) + ImGui::Separator(); + ImGui::TreePop(); + } + // Create multiple items in a same cell before switching to next column if (ImGui::TreeNode("Mixed items")) { @@ -2472,32 +2498,6 @@ ImGui::TreePop(); } - if (ImGui::TreeNode("Borders")) - { - // NB: Future columns API should allow automatic horizontal borders. - static bool h_borders = true; - static bool v_borders = true; - ImGui::Checkbox("horizontal", &h_borders); - ImGui::SameLine(); - ImGui::Checkbox("vertical", &v_borders); - ImGui::Columns(4, NULL, v_borders); - for (int i = 0; i < 4*3; i++) - { - if (h_borders && ImGui::GetColumnIndex() == 0) - ImGui::Separator(); - ImGui::Text("%c%c%c", 'a'+i, 'a'+i, 'a'+i); - ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); - ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); - ImGui::Text("Long text that is likely to clip"); - ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); - ImGui::NextColumn(); - } - ImGui::Columns(1); - if (h_borders) - ImGui::Separator(); - ImGui::TreePop(); - } - // Scrolling columns /* if (ImGui::TreeNode("Vertical Scrolling")) diff --git a/imgui.cpp b/imgui.cpp index 779ea09..a75829e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1140,7 +1140,7 @@ ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 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 @@ -5452,6 +5452,7 @@ window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y); window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize))); window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y); + // Setup drawing context // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x; @@ -8434,12 +8435,12 @@ static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm) { - return offset_norm * (columns->MaxX - columns->MinX); + return offset_norm * (columns->OffMaxX - columns->OffMinX); } static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset) { - return offset / (columns->MaxX - columns->MinX); + return offset / (columns->OffMaxX - columns->OffMinX); } static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; @@ -8472,7 +8473,7 @@ IM_ASSERT(column_index < columns->Columns.Size); const float t = columns->Columns[column_index].OffsetNorm; - const float x_offset = ImLerp(columns->MinX, columns->MaxX, t); + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); return x_offset; } @@ -8515,8 +8516,8 @@ const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) - offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); - columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX); + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX); if (preserve_width) SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); @@ -8551,7 +8552,7 @@ ImGuiColumns* columns = window->DC.CurrentColumns; window->DrawList->ChannelsSetCurrent(0); int cmd_size = window->DrawList->CmdBuffer.Size; - PushClipRect(columns->BackupClipRect.Min, columns->BackupClipRect.Max, false); + PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd } @@ -8597,9 +8598,8 @@ IM_ASSERT(columns_count >= 1); IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported - ImGuiID id = GetColumnsID(str_id, columns_count); - // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); ImGuiColumns* columns = FindOrCreateColumns(window, id); IM_ASSERT(columns->ID == id); columns->Current = 0; @@ -8609,11 +8609,11 @@ // Set state for first column const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); - columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range - columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); - columns->BackupCursorPosY = window->DC.CursorPos.y; - columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x; - columns->BackupClipRect = window->ClipRect; + 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->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostClipRect = window->ClipRect; columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -8622,7 +8622,7 @@ if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) columns->Columns.resize(0); - // Initialize defaults + // Initialize default widths columns->IsFirstFrame = (columns->Columns.Size == 0); if (columns->Columns.Size == 0) { @@ -8668,17 +8668,19 @@ window->DrawList->ChannelsMerge(); } + const ImGuiColumnsFlags flags = columns->Flags; columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); window->DC.CursorPos.y = columns->LineMaxY; - if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) - window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy bool is_being_resized = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) + if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) { // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. - const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y); + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); int dragging_column = -1; for (int n = 1; n < columns->Count; n++) @@ -8693,7 +8695,7 @@ continue; bool hovered = false, held = false; - if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) + if (!(flags & ImGuiColumnsFlags_NoResize)) { ButtonBehavior(column_hit_rect, column_id, &hovered, &held); if (hovered || held) @@ -8745,6 +8747,7 @@ BeginColumns(id, columns_count, flags); } + //----------------------------------------------------------------------------- // [SECTION] DRAG AND DROP //----------------------------------------------------------------------------- @@ -9692,7 +9695,7 @@ { if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) return; - ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); for (int column_n = 0; column_n < columns->Columns.Size; column_n++) ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); ImGui::TreePop(); diff --git a/imgui.h b/imgui.h index aafcb3a..0d46ec5 100644 --- a/imgui.h +++ b/imgui.h @@ -1293,7 +1293,7 @@ ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). - float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). 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. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1f01cc4..e0d9c76 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2426,6 +2426,32 @@ ImGui::TreePop(); } + if (ImGui::TreeNode("Borders")) + { + // NB: Future columns API should allow automatic horizontal borders. + static bool h_borders = true; + static bool v_borders = true; + ImGui::Checkbox("horizontal", &h_borders); + ImGui::SameLine(); + ImGui::Checkbox("vertical", &v_borders); + ImGui::Columns(4, NULL, v_borders); + for (int i = 0; i < 4 * 3; i++) + { + if (h_borders && ImGui::GetColumnIndex() == 0) + ImGui::Separator(); + ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); + ImGui::Text("Long text that is likely to clip"); + ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); + ImGui::NextColumn(); + } + ImGui::Columns(1); + if (h_borders) + ImGui::Separator(); + ImGui::TreePop(); + } + // Create multiple items in a same cell before switching to next column if (ImGui::TreeNode("Mixed items")) { @@ -2472,32 +2498,6 @@ ImGui::TreePop(); } - if (ImGui::TreeNode("Borders")) - { - // NB: Future columns API should allow automatic horizontal borders. - static bool h_borders = true; - static bool v_borders = true; - ImGui::Checkbox("horizontal", &h_borders); - ImGui::SameLine(); - ImGui::Checkbox("vertical", &v_borders); - ImGui::Columns(4, NULL, v_borders); - for (int i = 0; i < 4*3; i++) - { - if (h_borders && ImGui::GetColumnIndex() == 0) - ImGui::Separator(); - ImGui::Text("%c%c%c", 'a'+i, 'a'+i, 'a'+i); - ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); - ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); - ImGui::Text("Long text that is likely to clip"); - ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); - ImGui::NextColumn(); - } - ImGui::Columns(1); - if (h_borders) - ImGui::Separator(); - ImGui::TreePop(); - } - // Scrolling columns /* if (ImGui::TreeNode("Vertical Scrolling")) diff --git a/imgui_internal.h b/imgui_internal.h index 01f805b..b8bd9a6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -680,11 +680,11 @@ bool IsBeingResized; int Current; int Count; - float MinX, MaxX; + float OffMinX, OffMaxX; // Offsets from HostWorkRect.Min.x float LineMinY, LineMaxY; - float BackupCursorPosY; // Backup of CursorPos at the time of BeginColumns() - float BackupCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() - ImRect BackupClipRect; + float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns() + float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() + ImRect HostClipRect; // Backup of ClipRect at the time of BeginColumns() ImVector Columns; ImGuiColumns() { Clear(); } @@ -696,10 +696,10 @@ IsBeingResized = false; Current = 0; Count = 1; - MinX = MaxX = 0.0f; + OffMinX = OffMaxX = 0.0f; LineMinY = LineMaxY = 0.0f; - BackupCursorPosY = 0.0f; - BackupCursorMaxPosX = 0.0f; + HostCursorPosY = 0.0f; + HostCursorMaxPosX = 0.0f; Columns.clear(); } };