mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 05:01:05 +01:00 
			
		
		
		
	Internals: Refactor: Moved all Columns code from imgui.cpp to imgui_widgets.cpp (#125)
Also moved NextColumn between BeginColumn and NextColumn which makes it easier to work on that code.
This commit is contained in:
		
							
								
								
									
										391
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										391
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -75,7 +75,6 @@ CODE | ||||
| // [SECTION] TOOLTIPS | ||||
| // [SECTION] POPUPS | ||||
| // [SECTION] KEYBOARD/GAMEPAD NAVIGATION | ||||
| // [SECTION] COLUMNS | ||||
| // [SECTION] DRAG AND DROP | ||||
| // [SECTION] LOGGING/CAPTURING | ||||
| // [SECTION] SETTINGS | ||||
| @@ -8664,394 +8663,6 @@ void ImGui::NavUpdateWindowingList() | ||||
|     PopStyleVar(); | ||||
| } | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
| // [SECTION] COLUMNS | ||||
| // In the current version, Columns are very weak. Needs to be replaced with a more full-featured system. | ||||
| //----------------------------------------------------------------------------- | ||||
|  | ||||
| void ImGui::NextColumn() | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     if (window->SkipItems || window->DC.CurrentColumns == NULL) | ||||
|         return; | ||||
|  | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiColumns* columns = window->DC.CurrentColumns; | ||||
|  | ||||
|     if (columns->Count == 1) | ||||
|     { | ||||
|         window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); | ||||
|         IM_ASSERT(columns->Current == 0); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     PopItemWidth(); | ||||
|     PopClipRect(); | ||||
|  | ||||
|     columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); | ||||
|     if (++columns->Current < columns->Count) | ||||
|     { | ||||
|         // Columns 1+ cancel out IndentX | ||||
|         // FIXME-COLUMNS: Unnecessary, could be locked? | ||||
|         window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x; | ||||
|         window->DrawList->ChannelsSetCurrent(columns->Current + 1); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // New row/line | ||||
|         window->DC.ColumnsOffset.x = 0.0f; | ||||
|         window->DrawList->ChannelsSetCurrent(1); | ||||
|         columns->Current = 0; | ||||
|         columns->LineMinY = columns->LineMaxY; | ||||
|     } | ||||
|     window->DC.CursorPos.x = (float)(int)(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; | ||||
|  | ||||
|     PushColumnClipRect(columns->Current);     // FIXME-COLUMNS: Could it be an overwrite? | ||||
|  | ||||
|     // 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 - window->WindowPadding.x; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm) | ||||
| { | ||||
|     return offset_norm * (columns->OffMaxX - columns->OffMinX); | ||||
| } | ||||
|  | ||||
| static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset) | ||||
| { | ||||
|     return offset / (columns->OffMaxX - columns->OffMinX); | ||||
| } | ||||
|  | ||||
| static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; | ||||
|  | ||||
| static float GetDraggedColumnOffset(ImGuiColumns* 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 & ImGuiColumnsFlags_NoPreserveWidths)) | ||||
|         x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); | ||||
|  | ||||
|     return x; | ||||
| } | ||||
|  | ||||
| float ImGui::GetColumnOffset(int column_index) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindowRead(); | ||||
|     ImGuiColumns* columns = window->DC.CurrentColumns; | ||||
|     IM_ASSERT(columns != NULL); | ||||
|  | ||||
|     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(ImGuiColumns* 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 OffsetNormToPixels(columns, offset_norm); | ||||
| } | ||||
|  | ||||
| float ImGui::GetColumnWidth(int column_index) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindowRead(); | ||||
|     ImGuiColumns* columns = window->DC.CurrentColumns; | ||||
|     IM_ASSERT(columns != NULL); | ||||
|  | ||||
|     if (column_index < 0) | ||||
|         column_index = columns->Current; | ||||
|     return OffsetNormToPixels(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; | ||||
|     ImGuiColumns* 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 & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1); | ||||
|     const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; | ||||
|  | ||||
|     if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow)) | ||||
|         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)); | ||||
| } | ||||
|  | ||||
| void ImGui::SetColumnWidth(int column_index, float width) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindowRead(); | ||||
|     ImGuiColumns* 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(); | ||||
|     ImGuiColumns* columns = window->DC.CurrentColumns; | ||||
|     if (column_index < 0) | ||||
|         column_index = columns->Current; | ||||
|  | ||||
|     ImGuiColumnData* 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(); | ||||
|     ImGuiColumns* columns = window->DC.CurrentColumns; | ||||
|     window->DrawList->ChannelsSetCurrent(0); | ||||
|     int cmd_size = window->DrawList->CmdBuffer.Size; | ||||
|     PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false);  | ||||
|     IM_UNUSED(cmd_size); | ||||
|     IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd | ||||
| } | ||||
|  | ||||
| void ImGui::PopColumnsBackground() | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindowRead(); | ||||
|     ImGuiColumns* columns = window->DC.CurrentColumns; | ||||
|     window->DrawList->ChannelsSetCurrent(columns->Current + 1); | ||||
|     PopClipRect(); | ||||
| } | ||||
|  | ||||
| ImGuiColumns* 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(ImGuiColumns()); | ||||
|     ImGuiColumns* 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, ImGuiColumnsFlags 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); | ||||
|     ImGuiColumns* columns = FindOrCreateColumns(window, id); | ||||
|     IM_ASSERT(columns->ID == id); | ||||
|     columns->Current = 0; | ||||
|     columns->Count = columns_count; | ||||
|     columns->Flags = flags; | ||||
|     window->DC.CurrentColumns = columns; | ||||
|  | ||||
|     // Set state for first column | ||||
|     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; | ||||
|     columns->HostWorkRect = window->WorkRect; | ||||
|     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); | ||||
|  | ||||
|     // 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++) | ||||
|         { | ||||
|             ImGuiColumnData column; | ||||
|             column.OffsetNorm = n / (float)columns_count; | ||||
|             columns->Columns.push_back(column); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int n = 0; n < columns_count; n++) | ||||
|     { | ||||
|         // Compute clipping rectangle | ||||
|         ImGuiColumnData* column = &columns->Columns[n]; | ||||
|         float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n)); | ||||
|         float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f); | ||||
|         column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); | ||||
|         column->ClipRect.ClipWith(window->ClipRect); | ||||
|     } | ||||
|  | ||||
|     if (columns->Count > 1) | ||||
|     { | ||||
|         window->DrawList->ChannelsSplit(1 + columns->Count); | ||||
|         window->DrawList->ChannelsSetCurrent(1); | ||||
|         PushColumnClipRect(0); | ||||
|     } | ||||
|  | ||||
|     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 - window->WindowPadding.x; | ||||
| } | ||||
|  | ||||
| void ImGui::EndColumns() | ||||
| { | ||||
|     ImGuiContext& g = *GImGui; | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     ImGuiColumns* columns = window->DC.CurrentColumns; | ||||
|     IM_ASSERT(columns != NULL); | ||||
|  | ||||
|     PopItemWidth(); | ||||
|     if (columns->Count > 1) | ||||
|     { | ||||
|         PopClipRect(); | ||||
|         window->DrawList->ChannelsMerge(); | ||||
|     } | ||||
|  | ||||
|     const ImGuiColumnsFlags flags = columns->Flags; | ||||
|     columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); | ||||
|     window->DC.CursorPos.y = columns->LineMaxY; | ||||
|     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 (!(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->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++) | ||||
|         { | ||||
|             ImGuiColumnData* 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 & ImGuiColumnsFlags_NoResize)) | ||||
|             { | ||||
|                 ButtonBehavior(column_hit_rect, column_id, &hovered, &held); | ||||
|                 if (hovered || held) | ||||
|                     g.MouseCursor = ImGuiMouseCursor_ResizeEW; | ||||
|                 if (held && !(column->Flags & ImGuiColumnsFlags_NoResize)) | ||||
|                     dragging_column = n; | ||||
|             } | ||||
|  | ||||
|             // Draw column | ||||
|             const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); | ||||
|             const float xi = (float)(int)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 = columns->HostWorkRect; | ||||
|     window->DC.CurrentColumns = NULL; | ||||
|     window->DC.ColumnsOffset.x = 0.0f; | ||||
|     window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); | ||||
| } | ||||
|  | ||||
| // [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing] | ||||
| void ImGui::Columns(int columns_count, const char* id, bool border) | ||||
| { | ||||
|     ImGuiWindow* window = GetCurrentWindow(); | ||||
|     IM_ASSERT(columns_count >= 1); | ||||
|  | ||||
|     ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder); | ||||
|     //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior | ||||
|     ImGuiColumns* 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); | ||||
| } | ||||
|  | ||||
|  | ||||
| //----------------------------------------------------------------------------- | ||||
| // [SECTION] DRAG AND DROP | ||||
| @@ -10072,7 +9683,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) | ||||
|                 return; | ||||
|             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::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); | ||||
|             ImGui::TreePop(); | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user