This function reorder draw channels based on matching clip rectangle, to facilitate merging them. Called by EndTable(). For simplicity we call it TableMergeDrawChannels() but in fact it only reorder channels + overwrite ClipRect, actual merging is done by table->DrawSplitter.Merge() which is called right after TableMergeDrawChannels(). Columns where the contents didn't stray off their local clip
| 2396 | // |
| 2397 | // This function is particularly tricky to understand.. take a breath. |
| 2398 | void ImGui::TableMergeDrawChannels(ImGuiTable* table) |
| 2399 | { |
| 2400 | ImGuiContext& g = *GImGui; |
| 2401 | ImDrawListSplitter* splitter = table->DrawSplitter; |
| 2402 | const bool has_freeze_v = (table->FreezeRowsCount > 0); |
| 2403 | const bool has_freeze_h = (table->FreezeColumnsCount > 0); |
| 2404 | IM_ASSERT(splitter->_Current == 0); |
| 2405 | |
| 2406 | // Track which groups we are going to attempt to merge, and which channels goes into each group. |
| 2407 | struct MergeGroup |
| 2408 | { |
| 2409 | ImRect ClipRect; |
| 2410 | int ChannelsCount = 0; |
| 2411 | ImBitArrayPtr ChannelsMask = NULL; |
| 2412 | }; |
| 2413 | int merge_group_mask = 0x00; |
| 2414 | MergeGroup merge_groups[4]; |
| 2415 | |
| 2416 | // Use a reusable temp buffer for the merge masks as they are dynamically sized. |
| 2417 | const int max_draw_channels = (4 + table->ColumnsCount * 2); |
| 2418 | const int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels); |
| 2419 | g.TempBuffer.reserve(size_for_masks_bitarrays_one * 5); |
| 2420 | memset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5); |
| 2421 | for (int n = 0; n < IM_ARRAYSIZE(merge_groups); n++) |
| 2422 | merge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n)); |
| 2423 | ImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4)); |
| 2424 | |
| 2425 | // 1. Scan channels and take note of those which can be merged |
| 2426 | for (int column_n = 0; column_n < table->ColumnsCount; column_n++) |
| 2427 | { |
| 2428 | if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) |
| 2429 | continue; |
| 2430 | ImGuiTableColumn* column = &table->Columns[column_n]; |
| 2431 | |
| 2432 | const int merge_group_sub_count = has_freeze_v ? 2 : 1; |
| 2433 | for (int merge_group_sub_n = 0; merge_group_sub_n < merge_group_sub_count; merge_group_sub_n++) |
| 2434 | { |
| 2435 | const int channel_no = (merge_group_sub_n == 0) ? column->DrawChannelFrozen : column->DrawChannelUnfrozen; |
| 2436 | |
| 2437 | // Don't attempt to merge if there are multiple draw calls within the column |
| 2438 | ImDrawChannel* src_channel = &splitter->_Channels[channel_no]; |
| 2439 | if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() |
| 2440 | src_channel->_CmdBuffer.pop_back(); |
| 2441 | if (src_channel->_CmdBuffer.Size != 1) |
| 2442 | continue; |
| 2443 | |
| 2444 | // Find out the width of this merge group and check if it will fit in our column |
| 2445 | // (note that we assume that rendering didn't stray on the left direction. we should need a CursorMinPos to detect it) |
| 2446 | if (!(column->Flags & ImGuiTableColumnFlags_NoClip)) |
| 2447 | { |
| 2448 | float content_max_x; |
| 2449 | if (!has_freeze_v) |
| 2450 | content_max_x = ImMax(column->ContentMaxXUnfrozen, column->ContentMaxXHeadersUsed); // No row freeze |
| 2451 | else if (merge_group_sub_n == 0) |
| 2452 | content_max_x = ImMax(column->ContentMaxXFrozen, column->ContentMaxXHeadersUsed); // Row freeze: use width before freeze |
| 2453 | else |
| 2454 | content_max_x = column->ContentMaxXUnfrozen; // Row freeze: use width after freeze |
| 2455 | if (content_max_x > column->ClipRect.Max.x) |
nothing calls this directly
no test coverage detected