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
| 2625 | // |
| 2626 | // This function is particularly tricky to understand.. take a breath. |
| 2627 | void ImGui::TableMergeDrawChannels(ImGuiTable* table) |
| 2628 | { |
| 2629 | ImGuiContext& g = *GImGui; |
| 2630 | ImDrawListSplitter* splitter = table->DrawSplitter; |
| 2631 | const bool has_freeze_v = (table->FreezeRowsCount > 0); |
| 2632 | const bool has_freeze_h = (table->FreezeColumnsCount > 0); |
| 2633 | IM_ASSERT(splitter->_Current == 0); |
| 2634 | |
| 2635 | // Track which groups we are going to attempt to merge, and which channels goes into each group. |
| 2636 | struct MergeGroup |
| 2637 | { |
| 2638 | ImRect ClipRect; |
| 2639 | int ChannelsCount = 0; |
| 2640 | ImBitArrayPtr ChannelsMask = NULL; |
| 2641 | }; |
| 2642 | int merge_group_mask = 0x00; |
| 2643 | MergeGroup merge_groups[4]; |
| 2644 | |
| 2645 | // Use a reusable temp buffer for the merge masks as they are dynamically sized. |
| 2646 | const int max_draw_channels = (4 + table->ColumnsCount * 2); |
| 2647 | const int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels); |
| 2648 | g.TempBuffer.reserve(size_for_masks_bitarrays_one * 5); |
| 2649 | memset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5); |
| 2650 | for (int n = 0; n < IM_COUNTOF(merge_groups); n++) |
| 2651 | merge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n)); |
| 2652 | ImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4)); |
| 2653 | |
| 2654 | // 1. Scan channels and take note of those which can be merged |
| 2655 | for (int column_n = 0; column_n < table->ColumnsCount; column_n++) |
| 2656 | { |
| 2657 | if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) |
| 2658 | continue; |
| 2659 | ImGuiTableColumn* column = &table->Columns[column_n]; |
| 2660 | |
| 2661 | const int merge_group_sub_count = has_freeze_v ? 2 : 1; |
| 2662 | for (int merge_group_sub_n = 0; merge_group_sub_n < merge_group_sub_count; merge_group_sub_n++) |
| 2663 | { |
| 2664 | const int channel_no = (merge_group_sub_n == 0) ? column->DrawChannelFrozen : column->DrawChannelUnfrozen; |
| 2665 | |
| 2666 | // Don't attempt to merge if there are multiple draw calls within the column |
| 2667 | ImDrawChannel* src_channel = &splitter->_Channels[channel_no]; |
| 2668 | if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() |
| 2669 | src_channel->_CmdBuffer.pop_back(); |
| 2670 | if (src_channel->_CmdBuffer.Size != 1) |
| 2671 | continue; |
| 2672 | |
| 2673 | // Find out the width of this merge group and check if it will fit in our column |
| 2674 | // (note that we assume that rendering didn't stray on the left direction. we should need a CursorMinPos to detect it) |
| 2675 | if (!(column->Flags & ImGuiTableColumnFlags_NoClip)) |
| 2676 | { |
| 2677 | float content_max_x; |
| 2678 | if (!has_freeze_v) |
| 2679 | content_max_x = ImMax(column->ContentMaxXUnfrozen, column->ContentMaxXHeadersUsed); // No row freeze |
| 2680 | else if (merge_group_sub_n == 0) |
| 2681 | content_max_x = ImMax(column->ContentMaxXFrozen, column->ContentMaxXHeadersUsed); // Row freeze: use width before freeze |
| 2682 | else |
| 2683 | content_max_x = column->ContentMaxXUnfrozen; // Row freeze: use width after freeze |
| 2684 | if (content_max_x > column->ClipRect.Max.x) |
nothing calls this directly
no test coverage detected