mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-30 04:31:06 +01:00 
			
		
		
		
	Tables: Moving legacy Columns code
This commit is contained in:
		
							
								
								
									
										434
									
								
								imgui_tables.cpp
									
									
									
									
									
								
							
							
						
						
									
										434
									
								
								imgui_tables.cpp
									
									
									
									
									
								
							| @@ -66,6 +66,440 @@ | |||||||
| // [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. | // [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. | ||||||
| // (This is a legacy API, prefer using BeginTable/EndTable!) | // (This is a legacy API, prefer using BeginTable/EndTable!) | ||||||
| //------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||||
|  | // - SetWindowClipRectBeforeSetChannel() [Internal] | ||||||
|  | // - GetColumnIndex() | ||||||
|  | // - GetColumnsCount() | ||||||
|  | // - GetColumnOffset() | ||||||
|  | // - GetColumnWidth() | ||||||
|  | // - SetColumnOffset() | ||||||
|  | // - SetColumnWidth() | ||||||
|  | // - PushColumnClipRect() [Internal] | ||||||
|  | // - PushColumnsBackground() [Internal] | ||||||
|  | // - PopColumnsBackground() [Internal] | ||||||
|  | // - FindOrCreateColumns() [Internal] | ||||||
|  | // - GetColumnsID() [Internal] | ||||||
|  | // - BeginColumns() | ||||||
|  | // - NextColumn() | ||||||
|  | // - EndColumns() | ||||||
|  | // - Columns() | ||||||
|  | //------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | // [Internal] Small optimization to avoid calls to PopClipRect/SetCurrentChannel/PushClipRect in sequences, | ||||||
|  | // they would meddle many times with the underlying ImDrawCmd. | ||||||
|  | // Instead, we do a preemptive overwrite of clipping rectangle _without_ altering the command-buffer and let | ||||||
|  | // the subsequent single call to SetCurrentChannel() does it things once. | ||||||
|  | void ImGui::SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect) | ||||||
|  | { | ||||||
|  |     ImVec4 clip_rect_vec4 = clip_rect.ToVec4(); | ||||||
|  |     window->ClipRect = clip_rect; | ||||||
|  |     window->DrawList->_CmdHeader.ClipRect = clip_rect_vec4; | ||||||
|  |     window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 1] = clip_rect_vec4; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int ImGui::GetColumnIndex() | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindowRead(); | ||||||
|  |     return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int ImGui::GetColumnsCount() | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindowRead(); | ||||||
|  |     return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float ImGui::GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm) | ||||||
|  | { | ||||||
|  |     return offset_norm * (columns->OffMaxX - columns->OffMinX); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float ImGui::GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset) | ||||||
|  | { | ||||||
|  |     return offset / (columns->OffMaxX - columns->OffMinX); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; | ||||||
|  |  | ||||||
|  | static float GetDraggedColumnOffset(ImGuiOldColumns* columns, 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. | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     ImGuiWindow* window = g.CurrentWindow; | ||||||
|  |     IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. | ||||||
|  |     IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); | ||||||
|  |  | ||||||
|  |     float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; | ||||||
|  |     x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); | ||||||
|  |     if ((columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths)) | ||||||
|  |         x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); | ||||||
|  |  | ||||||
|  |     return x; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float ImGui::GetColumnOffset(int column_index) | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindowRead(); | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     if (columns == NULL) | ||||||
|  |         return 0.0f; | ||||||
|  |  | ||||||
|  |     if (column_index < 0) | ||||||
|  |         column_index = columns->Current; | ||||||
|  |     IM_ASSERT(column_index < columns->Columns.Size); | ||||||
|  |  | ||||||
|  |     const float t = columns->Columns[column_index].OffsetNorm; | ||||||
|  |     const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); | ||||||
|  |     return x_offset; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static float GetColumnWidthEx(ImGuiOldColumns* columns, int column_index, bool before_resize = false) | ||||||
|  | { | ||||||
|  |     if (column_index < 0) | ||||||
|  |         column_index = columns->Current; | ||||||
|  |  | ||||||
|  |     float offset_norm; | ||||||
|  |     if (before_resize) | ||||||
|  |         offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; | ||||||
|  |     else | ||||||
|  |         offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; | ||||||
|  |     return ImGui::GetColumnOffsetFromNorm(columns, offset_norm); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float ImGui::GetColumnWidth(int column_index) | ||||||
|  | { | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     ImGuiWindow* window = g.CurrentWindow; | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     if (columns == NULL) | ||||||
|  |         return GetContentRegionAvail().x; | ||||||
|  |  | ||||||
|  |     if (column_index < 0) | ||||||
|  |         column_index = columns->Current; | ||||||
|  |     return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::SetColumnOffset(int column_index, float offset) | ||||||
|  | { | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     ImGuiWindow* window = g.CurrentWindow; | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     IM_ASSERT(columns != NULL); | ||||||
|  |  | ||||||
|  |     if (column_index < 0) | ||||||
|  |         column_index = columns->Current; | ||||||
|  |     IM_ASSERT(column_index < columns->Columns.Size); | ||||||
|  |  | ||||||
|  |     const bool preserve_width = !(columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths) && (column_index < columns->Count - 1); | ||||||
|  |     const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; | ||||||
|  |  | ||||||
|  |     if (!(columns->Flags & ImGuiOldColumnFlags_NoForceWithinWindow)) | ||||||
|  |         offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); | ||||||
|  |     columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX); | ||||||
|  |  | ||||||
|  |     if (preserve_width) | ||||||
|  |         SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::SetColumnWidth(int column_index, float width) | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindowRead(); | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     IM_ASSERT(columns != NULL); | ||||||
|  |  | ||||||
|  |     if (column_index < 0) | ||||||
|  |         column_index = columns->Current; | ||||||
|  |     SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::PushColumnClipRect(int column_index) | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindowRead(); | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     if (column_index < 0) | ||||||
|  |         column_index = columns->Current; | ||||||
|  |  | ||||||
|  |     ImGuiOldColumnData* column = &columns->Columns[column_index]; | ||||||
|  |     PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) | ||||||
|  | void ImGui::PushColumnsBackground() | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindowRead(); | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     if (columns->Count == 1) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     // Optimization: avoid SetCurrentChannel() + PushClipRect() | ||||||
|  |     columns->HostBackupClipRect = window->ClipRect; | ||||||
|  |     SetWindowClipRectBeforeSetChannel(window, columns->HostInitialClipRect); | ||||||
|  |     columns->Splitter.SetCurrentChannel(window->DrawList, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::PopColumnsBackground() | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindowRead(); | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     if (columns->Count == 1) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     // Optimization: avoid PopClipRect() + SetCurrentChannel() | ||||||
|  |     SetWindowClipRectBeforeSetChannel(window, columns->HostBackupClipRect); | ||||||
|  |     columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ImGuiOldColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) | ||||||
|  | { | ||||||
|  |     // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. | ||||||
|  |     for (int n = 0; n < window->ColumnsStorage.Size; n++) | ||||||
|  |         if (window->ColumnsStorage[n].ID == id) | ||||||
|  |             return &window->ColumnsStorage[n]; | ||||||
|  |  | ||||||
|  |     window->ColumnsStorage.push_back(ImGuiOldColumns()); | ||||||
|  |     ImGuiOldColumns* columns = &window->ColumnsStorage.back(); | ||||||
|  |     columns->ID = id; | ||||||
|  |     return columns; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count) | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindow(); | ||||||
|  |  | ||||||
|  |     // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. | ||||||
|  |     // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. | ||||||
|  |     PushID(0x11223347 + (str_id ? 0 : columns_count)); | ||||||
|  |     ImGuiID id = window->GetID(str_id ? str_id : "columns"); | ||||||
|  |     PopID(); | ||||||
|  |  | ||||||
|  |     return id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFlags flags) | ||||||
|  | { | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     ImGuiWindow* window = GetCurrentWindow(); | ||||||
|  |  | ||||||
|  |     IM_ASSERT(columns_count >= 1); | ||||||
|  |     IM_ASSERT(window->DC.CurrentColumns == NULL);   // Nested columns are currently not supported | ||||||
|  |  | ||||||
|  |     // Acquire storage for the columns set | ||||||
|  |     ImGuiID id = GetColumnsID(str_id, columns_count); | ||||||
|  |     ImGuiOldColumns* columns = FindOrCreateColumns(window, id); | ||||||
|  |     IM_ASSERT(columns->ID == id); | ||||||
|  |     columns->Current = 0; | ||||||
|  |     columns->Count = columns_count; | ||||||
|  |     columns->Flags = flags; | ||||||
|  |     window->DC.CurrentColumns = columns; | ||||||
|  |  | ||||||
|  |     columns->HostCursorPosY = window->DC.CursorPos.y; | ||||||
|  |     columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; | ||||||
|  |     columns->HostInitialClipRect = window->ClipRect; | ||||||
|  |     columns->HostBackupParentWorkRect = window->ParentWorkRect; | ||||||
|  |     window->ParentWorkRect = window->WorkRect; | ||||||
|  |  | ||||||
|  |     // Set state for first column | ||||||
|  |     // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect | ||||||
|  |     const float column_padding = g.Style.ItemSpacing.x; | ||||||
|  |     const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize)); | ||||||
|  |     const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f); | ||||||
|  |     const float max_2 = window->WorkRect.Max.x + half_clip_extend_x; | ||||||
|  |     columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f); | ||||||
|  |     columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f); | ||||||
|  |     columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; | ||||||
|  |  | ||||||
|  |     // Clear data if columns count changed | ||||||
|  |     if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) | ||||||
|  |         columns->Columns.resize(0); | ||||||
|  |  | ||||||
|  |     // Initialize default widths | ||||||
|  |     columns->IsFirstFrame = (columns->Columns.Size == 0); | ||||||
|  |     if (columns->Columns.Size == 0) | ||||||
|  |     { | ||||||
|  |         columns->Columns.reserve(columns_count + 1); | ||||||
|  |         for (int n = 0; n < columns_count + 1; n++) | ||||||
|  |         { | ||||||
|  |             ImGuiOldColumnData column; | ||||||
|  |             column.OffsetNorm = n / (float)columns_count; | ||||||
|  |             columns->Columns.push_back(column); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (int n = 0; n < columns_count; n++) | ||||||
|  |     { | ||||||
|  |         // Compute clipping rectangle | ||||||
|  |         ImGuiOldColumnData* column = &columns->Columns[n]; | ||||||
|  |         float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); | ||||||
|  |         float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); | ||||||
|  |         column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); | ||||||
|  |         column->ClipRect.ClipWithFull(window->ClipRect); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (columns->Count > 1) | ||||||
|  |     { | ||||||
|  |         columns->Splitter.Split(window->DrawList, 1 + columns->Count); | ||||||
|  |         columns->Splitter.SetCurrentChannel(window->DrawList, 1); | ||||||
|  |         PushColumnClipRect(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. | ||||||
|  |     float offset_0 = GetColumnOffset(columns->Current); | ||||||
|  |     float offset_1 = GetColumnOffset(columns->Current + 1); | ||||||
|  |     float width = offset_1 - offset_0; | ||||||
|  |     PushItemWidth(width * 0.65f); | ||||||
|  |     window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); | ||||||
|  |     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); | ||||||
|  |     window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::NextColumn() | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindow(); | ||||||
|  |     if (window->SkipItems || window->DC.CurrentColumns == NULL) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |  | ||||||
|  |     if (columns->Count == 1) | ||||||
|  |     { | ||||||
|  |         window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); | ||||||
|  |         IM_ASSERT(columns->Current == 0); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Next column | ||||||
|  |     if (++columns->Current == columns->Count) | ||||||
|  |         columns->Current = 0; | ||||||
|  |  | ||||||
|  |     PopItemWidth(); | ||||||
|  |  | ||||||
|  |     // Optimization: avoid PopClipRect() + SetCurrentChannel() + PushClipRect() | ||||||
|  |     // (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them), | ||||||
|  |     ImGuiOldColumnData* column = &columns->Columns[columns->Current]; | ||||||
|  |     SetWindowClipRectBeforeSetChannel(window, column->ClipRect); | ||||||
|  |     columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); | ||||||
|  |  | ||||||
|  |     const float column_padding = g.Style.ItemSpacing.x; | ||||||
|  |     columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); | ||||||
|  |     if (columns->Current > 0) | ||||||
|  |     { | ||||||
|  |         // Columns 1+ ignore IndentX (by canceling it out) | ||||||
|  |         // FIXME-COLUMNS: Unnecessary, could be locked? | ||||||
|  |         window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         // New row/line: column 0 honor IndentX. | ||||||
|  |         window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); | ||||||
|  |         columns->LineMinY = columns->LineMaxY; | ||||||
|  |     } | ||||||
|  |     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); | ||||||
|  |     window->DC.CursorPos.y = columns->LineMinY; | ||||||
|  |     window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); | ||||||
|  |     window->DC.CurrLineTextBaseOffset = 0.0f; | ||||||
|  |  | ||||||
|  |     // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. | ||||||
|  |     float offset_0 = GetColumnOffset(columns->Current); | ||||||
|  |     float offset_1 = GetColumnOffset(columns->Current + 1); | ||||||
|  |     float width = offset_1 - offset_0; | ||||||
|  |     PushItemWidth(width * 0.65f); | ||||||
|  |     window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::EndColumns() | ||||||
|  | { | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     ImGuiWindow* window = GetCurrentWindow(); | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     IM_ASSERT(columns != NULL); | ||||||
|  |  | ||||||
|  |     PopItemWidth(); | ||||||
|  |     if (columns->Count > 1) | ||||||
|  |     { | ||||||
|  |         PopClipRect(); | ||||||
|  |         columns->Splitter.Merge(window->DrawList); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const ImGuiOldColumnFlags flags = columns->Flags; | ||||||
|  |     columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); | ||||||
|  |     window->DC.CursorPos.y = columns->LineMaxY; | ||||||
|  |     if (!(flags & ImGuiOldColumnFlags_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 (!(flags & ImGuiOldColumnFlags_NoBorder) && !window->SkipItems) | ||||||
|  |     { | ||||||
|  |         // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. | ||||||
|  |         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++) | ||||||
|  |         { | ||||||
|  |             ImGuiOldColumnData* column = &columns->Columns[n]; | ||||||
|  |             float x = window->Pos.x + GetColumnOffset(n); | ||||||
|  |             const ImGuiID column_id = columns->ID + ImGuiID(n); | ||||||
|  |             const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; | ||||||
|  |             const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); | ||||||
|  |             KeepAliveID(column_id); | ||||||
|  |             if (IsClippedEx(column_hit_rect, column_id, false)) | ||||||
|  |                 continue; | ||||||
|  |  | ||||||
|  |             bool hovered = false, held = false; | ||||||
|  |             if (!(flags & ImGuiOldColumnFlags_NoResize)) | ||||||
|  |             { | ||||||
|  |                 ButtonBehavior(column_hit_rect, column_id, &hovered, &held); | ||||||
|  |                 if (hovered || held) | ||||||
|  |                     g.MouseCursor = ImGuiMouseCursor_ResizeEW; | ||||||
|  |                 if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize)) | ||||||
|  |                     dragging_column = n; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Draw column | ||||||
|  |             const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); | ||||||
|  |             const float xi = IM_FLOOR(x); | ||||||
|  |             window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. | ||||||
|  |         if (dragging_column != -1) | ||||||
|  |         { | ||||||
|  |             if (!columns->IsBeingResized) | ||||||
|  |                 for (int n = 0; n < columns->Count + 1; n++) | ||||||
|  |                     columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; | ||||||
|  |             columns->IsBeingResized = is_being_resized = true; | ||||||
|  |             float x = GetDraggedColumnOffset(columns, dragging_column); | ||||||
|  |             SetColumnOffset(dragging_column, x); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     columns->IsBeingResized = is_being_resized; | ||||||
|  |  | ||||||
|  |     window->WorkRect = window->ParentWorkRect; | ||||||
|  |     window->ParentWorkRect = columns->HostBackupParentWorkRect; | ||||||
|  |     window->DC.CurrentColumns = NULL; | ||||||
|  |     window->DC.ColumnsOffset.x = 0.0f; | ||||||
|  |     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ImGui::Columns(int columns_count, const char* id, bool border) | ||||||
|  | { | ||||||
|  |     ImGuiWindow* window = GetCurrentWindow(); | ||||||
|  |     IM_ASSERT(columns_count >= 1); | ||||||
|  |  | ||||||
|  |     ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder); | ||||||
|  |     //flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior | ||||||
|  |     ImGuiOldColumns* columns = window->DC.CurrentColumns; | ||||||
|  |     if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) | ||||||
|  |         return; | ||||||
|  |  | ||||||
|  |     if (columns != NULL) | ||||||
|  |         EndColumns(); | ||||||
|  |  | ||||||
|  |     if (columns_count != 1) | ||||||
|  |         BeginColumns(id, columns_count, flags); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||||
|   | |||||||
| @@ -7866,445 +7866,4 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------- |  | ||||||
| // [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. |  | ||||||
| // In the current version, Columns are very weak. Needs to be replaced with a more full-featured system. |  | ||||||
| //------------------------------------------------------------------------- |  | ||||||
| // - SetWindowClipRectBeforeSetChannel() [Internal] |  | ||||||
| // - GetColumnIndex() |  | ||||||
| // - GetColumnCount() |  | ||||||
| // - GetColumnOffset() |  | ||||||
| // - GetColumnWidth() |  | ||||||
| // - SetColumnOffset() |  | ||||||
| // - SetColumnWidth() |  | ||||||
| // - PushColumnClipRect() [Internal] |  | ||||||
| // - PushColumnsBackground() [Internal] |  | ||||||
| // - PopColumnsBackground() [Internal] |  | ||||||
| // - FindOrCreateColumns() [Internal] |  | ||||||
| // - GetColumnsID() [Internal] |  | ||||||
| // - BeginColumns() |  | ||||||
| // - NextColumn() |  | ||||||
| // - EndColumns() |  | ||||||
| // - Columns() |  | ||||||
| //------------------------------------------------------------------------- |  | ||||||
|  |  | ||||||
| // [Internal] Small optimization to avoid calls to PopClipRect/SetCurrentChannel/PushClipRect in sequences, |  | ||||||
| // they would meddle many times with the underlying ImDrawCmd. |  | ||||||
| // Instead, we do a preemptive overwrite of clipping rectangle _without_ altering the command-buffer and let |  | ||||||
| // the subsequent single call to SetCurrentChannel() does it things once. |  | ||||||
| void ImGui::SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect) |  | ||||||
| { |  | ||||||
|     ImVec4 clip_rect_vec4 = clip_rect.ToVec4(); |  | ||||||
|     window->ClipRect = clip_rect; |  | ||||||
|     window->DrawList->_CmdHeader.ClipRect = clip_rect_vec4; |  | ||||||
|     window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 1] = clip_rect_vec4; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int ImGui::GetColumnIndex() |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindowRead(); |  | ||||||
|     return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int ImGui::GetColumnsCount() |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindowRead(); |  | ||||||
|     return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| float ImGui::GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm) |  | ||||||
| { |  | ||||||
|     return offset_norm * (columns->OffMaxX - columns->OffMinX); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| float ImGui::GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset) |  | ||||||
| { |  | ||||||
|     return offset / (columns->OffMaxX - columns->OffMinX); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; |  | ||||||
|  |  | ||||||
| static float GetDraggedColumnOffset(ImGuiOldColumns* columns, 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. |  | ||||||
|     ImGuiContext& g = *GImGui; |  | ||||||
|     ImGuiWindow* window = g.CurrentWindow; |  | ||||||
|     IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. |  | ||||||
|     IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); |  | ||||||
|  |  | ||||||
|     float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; |  | ||||||
|     x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); |  | ||||||
|     if ((columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths)) |  | ||||||
|         x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); |  | ||||||
|  |  | ||||||
|     return x; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| float ImGui::GetColumnOffset(int column_index) |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindowRead(); |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     if (columns == NULL) |  | ||||||
|         return 0.0f; |  | ||||||
|  |  | ||||||
|     if (column_index < 0) |  | ||||||
|         column_index = columns->Current; |  | ||||||
|     IM_ASSERT(column_index < columns->Columns.Size); |  | ||||||
|  |  | ||||||
|     const float t = columns->Columns[column_index].OffsetNorm; |  | ||||||
|     const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); |  | ||||||
|     return x_offset; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static float GetColumnWidthEx(ImGuiOldColumns* columns, int column_index, bool before_resize = false) |  | ||||||
| { |  | ||||||
|     if (column_index < 0) |  | ||||||
|         column_index = columns->Current; |  | ||||||
|  |  | ||||||
|     float offset_norm; |  | ||||||
|     if (before_resize) |  | ||||||
|         offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; |  | ||||||
|     else |  | ||||||
|         offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; |  | ||||||
|     return ImGui::GetColumnOffsetFromNorm(columns, offset_norm); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| float ImGui::GetColumnWidth(int column_index) |  | ||||||
| { |  | ||||||
|     ImGuiContext& g = *GImGui; |  | ||||||
|     ImGuiWindow* window = g.CurrentWindow; |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     if (columns == NULL) |  | ||||||
|         return GetContentRegionAvail().x; |  | ||||||
|  |  | ||||||
|     if (column_index < 0) |  | ||||||
|         column_index = columns->Current; |  | ||||||
|     return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::SetColumnOffset(int column_index, float offset) |  | ||||||
| { |  | ||||||
|     ImGuiContext& g = *GImGui; |  | ||||||
|     ImGuiWindow* window = g.CurrentWindow; |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     IM_ASSERT(columns != NULL); |  | ||||||
|  |  | ||||||
|     if (column_index < 0) |  | ||||||
|         column_index = columns->Current; |  | ||||||
|     IM_ASSERT(column_index < columns->Columns.Size); |  | ||||||
|  |  | ||||||
|     const bool preserve_width = !(columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths) && (column_index < columns->Count - 1); |  | ||||||
|     const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; |  | ||||||
|  |  | ||||||
|     if (!(columns->Flags & ImGuiOldColumnFlags_NoForceWithinWindow)) |  | ||||||
|         offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); |  | ||||||
|     columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX); |  | ||||||
|  |  | ||||||
|     if (preserve_width) |  | ||||||
|         SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::SetColumnWidth(int column_index, float width) |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindowRead(); |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     IM_ASSERT(columns != NULL); |  | ||||||
|  |  | ||||||
|     if (column_index < 0) |  | ||||||
|         column_index = columns->Current; |  | ||||||
|     SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::PushColumnClipRect(int column_index) |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindowRead(); |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     if (column_index < 0) |  | ||||||
|         column_index = columns->Current; |  | ||||||
|  |  | ||||||
|     ImGuiOldColumnData* column = &columns->Columns[column_index]; |  | ||||||
|     PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) |  | ||||||
| void ImGui::PushColumnsBackground() |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindowRead(); |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     if (columns->Count == 1) |  | ||||||
|         return; |  | ||||||
|  |  | ||||||
|     // Optimization: avoid SetCurrentChannel() + PushClipRect() |  | ||||||
|     columns->HostBackupClipRect = window->ClipRect; |  | ||||||
|     SetWindowClipRectBeforeSetChannel(window, columns->HostInitialClipRect); |  | ||||||
|     columns->Splitter.SetCurrentChannel(window->DrawList, 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::PopColumnsBackground() |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindowRead(); |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     if (columns->Count == 1) |  | ||||||
|         return; |  | ||||||
|  |  | ||||||
|     // Optimization: avoid PopClipRect() + SetCurrentChannel() |  | ||||||
|     SetWindowClipRectBeforeSetChannel(window, columns->HostBackupClipRect); |  | ||||||
|     columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ImGuiOldColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) |  | ||||||
| { |  | ||||||
|     // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. |  | ||||||
|     for (int n = 0; n < window->ColumnsStorage.Size; n++) |  | ||||||
|         if (window->ColumnsStorage[n].ID == id) |  | ||||||
|             return &window->ColumnsStorage[n]; |  | ||||||
|  |  | ||||||
|     window->ColumnsStorage.push_back(ImGuiOldColumns()); |  | ||||||
|     ImGuiOldColumns* columns = &window->ColumnsStorage.back(); |  | ||||||
|     columns->ID = id; |  | ||||||
|     return columns; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count) |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindow(); |  | ||||||
|  |  | ||||||
|     // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. |  | ||||||
|     // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. |  | ||||||
|     PushID(0x11223347 + (str_id ? 0 : columns_count)); |  | ||||||
|     ImGuiID id = window->GetID(str_id ? str_id : "columns"); |  | ||||||
|     PopID(); |  | ||||||
|  |  | ||||||
|     return id; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFlags flags) |  | ||||||
| { |  | ||||||
|     ImGuiContext& g = *GImGui; |  | ||||||
|     ImGuiWindow* window = GetCurrentWindow(); |  | ||||||
|  |  | ||||||
|     IM_ASSERT(columns_count >= 1); |  | ||||||
|     IM_ASSERT(window->DC.CurrentColumns == NULL);   // Nested columns are currently not supported |  | ||||||
|  |  | ||||||
|     // Acquire storage for the columns set |  | ||||||
|     ImGuiID id = GetColumnsID(str_id, columns_count); |  | ||||||
|     ImGuiOldColumns* columns = FindOrCreateColumns(window, id); |  | ||||||
|     IM_ASSERT(columns->ID == id); |  | ||||||
|     columns->Current = 0; |  | ||||||
|     columns->Count = columns_count; |  | ||||||
|     columns->Flags = flags; |  | ||||||
|     window->DC.CurrentColumns = columns; |  | ||||||
|  |  | ||||||
|     columns->HostCursorPosY = window->DC.CursorPos.y; |  | ||||||
|     columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; |  | ||||||
|     columns->HostInitialClipRect = window->ClipRect; |  | ||||||
|     columns->HostBackupParentWorkRect = window->ParentWorkRect; |  | ||||||
|     window->ParentWorkRect = window->WorkRect; |  | ||||||
|  |  | ||||||
|     // Set state for first column |  | ||||||
|     // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect |  | ||||||
|     const float column_padding = g.Style.ItemSpacing.x; |  | ||||||
|     const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize)); |  | ||||||
|     const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f); |  | ||||||
|     const float max_2 = window->WorkRect.Max.x + half_clip_extend_x; |  | ||||||
|     columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f); |  | ||||||
|     columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f); |  | ||||||
|     columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; |  | ||||||
|  |  | ||||||
|     // Clear data if columns count changed |  | ||||||
|     if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) |  | ||||||
|         columns->Columns.resize(0); |  | ||||||
|  |  | ||||||
|     // Initialize default widths |  | ||||||
|     columns->IsFirstFrame = (columns->Columns.Size == 0); |  | ||||||
|     if (columns->Columns.Size == 0) |  | ||||||
|     { |  | ||||||
|         columns->Columns.reserve(columns_count + 1); |  | ||||||
|         for (int n = 0; n < columns_count + 1; n++) |  | ||||||
|         { |  | ||||||
|             ImGuiOldColumnData column; |  | ||||||
|             column.OffsetNorm = n / (float)columns_count; |  | ||||||
|             columns->Columns.push_back(column); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     for (int n = 0; n < columns_count; n++) |  | ||||||
|     { |  | ||||||
|         // Compute clipping rectangle |  | ||||||
|         ImGuiOldColumnData* column = &columns->Columns[n]; |  | ||||||
|         float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); |  | ||||||
|         float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); |  | ||||||
|         column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); |  | ||||||
|         column->ClipRect.ClipWithFull(window->ClipRect); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (columns->Count > 1) |  | ||||||
|     { |  | ||||||
|         columns->Splitter.Split(window->DrawList, 1 + columns->Count); |  | ||||||
|         columns->Splitter.SetCurrentChannel(window->DrawList, 1); |  | ||||||
|         PushColumnClipRect(0); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. |  | ||||||
|     float offset_0 = GetColumnOffset(columns->Current); |  | ||||||
|     float offset_1 = GetColumnOffset(columns->Current + 1); |  | ||||||
|     float width = offset_1 - offset_0; |  | ||||||
|     PushItemWidth(width * 0.65f); |  | ||||||
|     window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); |  | ||||||
|     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); |  | ||||||
|     window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::NextColumn() |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindow(); |  | ||||||
|     if (window->SkipItems || window->DC.CurrentColumns == NULL) |  | ||||||
|         return; |  | ||||||
|  |  | ||||||
|     ImGuiContext& g = *GImGui; |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|  |  | ||||||
|     if (columns->Count == 1) |  | ||||||
|     { |  | ||||||
|         window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); |  | ||||||
|         IM_ASSERT(columns->Current == 0); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Next column |  | ||||||
|     if (++columns->Current == columns->Count) |  | ||||||
|         columns->Current = 0; |  | ||||||
|  |  | ||||||
|     PopItemWidth(); |  | ||||||
|  |  | ||||||
|     // Optimization: avoid PopClipRect() + SetCurrentChannel() + PushClipRect() |  | ||||||
|     // (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them), |  | ||||||
|     ImGuiOldColumnData* column = &columns->Columns[columns->Current]; |  | ||||||
|     SetWindowClipRectBeforeSetChannel(window, column->ClipRect); |  | ||||||
|     columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); |  | ||||||
|  |  | ||||||
|     const float column_padding = g.Style.ItemSpacing.x; |  | ||||||
|     columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); |  | ||||||
|     if (columns->Current > 0) |  | ||||||
|     { |  | ||||||
|         // Columns 1+ ignore IndentX (by canceling it out) |  | ||||||
|         // FIXME-COLUMNS: Unnecessary, could be locked? |  | ||||||
|         window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         // New row/line: column 0 honor IndentX. |  | ||||||
|         window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); |  | ||||||
|         columns->LineMinY = columns->LineMaxY; |  | ||||||
|     } |  | ||||||
|     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); |  | ||||||
|     window->DC.CursorPos.y = columns->LineMinY; |  | ||||||
|     window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); |  | ||||||
|     window->DC.CurrLineTextBaseOffset = 0.0f; |  | ||||||
|  |  | ||||||
|     // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. |  | ||||||
|     float offset_0 = GetColumnOffset(columns->Current); |  | ||||||
|     float offset_1 = GetColumnOffset(columns->Current + 1); |  | ||||||
|     float width = offset_1 - offset_0; |  | ||||||
|     PushItemWidth(width * 0.65f); |  | ||||||
|     window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::EndColumns() |  | ||||||
| { |  | ||||||
|     ImGuiContext& g = *GImGui; |  | ||||||
|     ImGuiWindow* window = GetCurrentWindow(); |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     IM_ASSERT(columns != NULL); |  | ||||||
|  |  | ||||||
|     PopItemWidth(); |  | ||||||
|     if (columns->Count > 1) |  | ||||||
|     { |  | ||||||
|         PopClipRect(); |  | ||||||
|         columns->Splitter.Merge(window->DrawList); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const ImGuiOldColumnFlags flags = columns->Flags; |  | ||||||
|     columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); |  | ||||||
|     window->DC.CursorPos.y = columns->LineMaxY; |  | ||||||
|     if (!(flags & ImGuiOldColumnFlags_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 (!(flags & ImGuiOldColumnFlags_NoBorder) && !window->SkipItems) |  | ||||||
|     { |  | ||||||
|         // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. |  | ||||||
|         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++) |  | ||||||
|         { |  | ||||||
|             ImGuiOldColumnData* column = &columns->Columns[n]; |  | ||||||
|             float x = window->Pos.x + GetColumnOffset(n); |  | ||||||
|             const ImGuiID column_id = columns->ID + ImGuiID(n); |  | ||||||
|             const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; |  | ||||||
|             const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); |  | ||||||
|             KeepAliveID(column_id); |  | ||||||
|             if (IsClippedEx(column_hit_rect, column_id, false)) |  | ||||||
|                 continue; |  | ||||||
|  |  | ||||||
|             bool hovered = false, held = false; |  | ||||||
|             if (!(flags & ImGuiOldColumnFlags_NoResize)) |  | ||||||
|             { |  | ||||||
|                 ButtonBehavior(column_hit_rect, column_id, &hovered, &held); |  | ||||||
|                 if (hovered || held) |  | ||||||
|                     g.MouseCursor = ImGuiMouseCursor_ResizeEW; |  | ||||||
|                 if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize)) |  | ||||||
|                     dragging_column = n; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // Draw column |  | ||||||
|             const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); |  | ||||||
|             const float xi = IM_FLOOR(x); |  | ||||||
|             window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. |  | ||||||
|         if (dragging_column != -1) |  | ||||||
|         { |  | ||||||
|             if (!columns->IsBeingResized) |  | ||||||
|                 for (int n = 0; n < columns->Count + 1; n++) |  | ||||||
|                     columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; |  | ||||||
|             columns->IsBeingResized = is_being_resized = true; |  | ||||||
|             float x = GetDraggedColumnOffset(columns, dragging_column); |  | ||||||
|             SetColumnOffset(dragging_column, x); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     columns->IsBeingResized = is_being_resized; |  | ||||||
|  |  | ||||||
|     window->WorkRect = window->ParentWorkRect; |  | ||||||
|     window->ParentWorkRect = columns->HostBackupParentWorkRect; |  | ||||||
|     window->DC.CurrentColumns = NULL; |  | ||||||
|     window->DC.ColumnsOffset.x = 0.0f; |  | ||||||
|     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void ImGui::Columns(int columns_count, const char* id, bool border) |  | ||||||
| { |  | ||||||
|     ImGuiWindow* window = GetCurrentWindow(); |  | ||||||
|     IM_ASSERT(columns_count >= 1); |  | ||||||
|  |  | ||||||
|     ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder); |  | ||||||
|     //flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior |  | ||||||
|     ImGuiOldColumns* columns = window->DC.CurrentColumns; |  | ||||||
|     if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) |  | ||||||
|         return; |  | ||||||
|  |  | ||||||
|     if (columns != NULL) |  | ||||||
|         EndColumns(); |  | ||||||
|  |  | ||||||
|     if (columns_count != 1) |  | ||||||
|         BeginColumns(id, columns_count, flags); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------- |  | ||||||
|  |  | ||||||
| #endif // #ifndef IMGUI_DISABLE | #endif // #ifndef IMGUI_DISABLE | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user