Version/Branch of Dear ImGui:1.62 (current master)
My Issue/Question:
I'm trying to visually cluster groups of widgets (see https://github.com/ocornut/imgui/issues/1496) (basically enclose them into some sort of box with a bacgrkound color) and to do so I found myself having to draw "out of order". I need to be able to draw behind a selected group of widgets; and I looked into the ChannelsSplit(). It's a very neat solution, but I found that columns are already "under the effect" of split channels, so you are not allowed to split channels when inside a column.
In the example below, ImGui throws an assert when doing ImGui::ChannelsSplit(2); bc we already are under a split.
ImGui::Begin("My Window", &active); /////////////////////////////////////////////////////////////
ImGui::SetWindowSize(ImVec2(500, 500), ImGuiCond_Once);
ImGui::Separator();
ImGui::Columns(2);
ImGui::Text("col 1");
ImGui::GetWindowDrawList()->ChannelsSplit(2);
ImGui::GetWindowDrawList()->ChannelsSetCurrent(1);
ImGui::BeginGroup();
if (ImGui::CollapsingHeader("My Group", ImGuiTreeNodeFlags_DefaultOpen)){
ImGui::SliderFloat("val1", &myVal[0], 0, 1);
ImGui::SliderFloat("val2", &myVal[1], 0, 1);
ImGui::SliderFloat("val3", &myVal[2], 0, 1);
ImGui::SliderFloat("val4", &myVal[3], 0, 1);
}
ImGui::EndGroup();
ImGui::GetWindowDrawList()->ChannelsSetCurrent(0);
ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,0,0,64), 5);
ImGui::GetWindowDrawList()->ChannelsMerge();
ImGui::NextColumn();
ImGui::Text("col 2");
ImGui::SliderFloat("val1", &myVal[4], 0, 1);
ImGui::SliderFloat("val2", &myVal[5], 0, 1);
ImGui::SliderFloat("val3", &myVal[6], 0, 1);
ImGui::SliderFloat("val4", &myVal[7], 0, 1);
ImGui::Columns(1);
ImGui::End(); //////////////////////////////////////////////////////////////////////////////////
As a workaround, I've been merging the current split (introduced by the column), storing the # of channels and the current channel... drawing my custom stuff under a new split, and closing it, and re-opemning the column split. Seems to work but feels very hacky... (see the hack below, wrapped within /**/ sections
ImGui::Begin("My Window", &active); /////////////////////////////////////////////////////////////
ImGui::SetWindowSize(ImVec2(500, 500), ImGuiCond_Once);
ImGui::Separator();
ImGui::Columns(2);
ImGui::Text("col 1");
/* hack begin 1 */
int pervChan = ImGui::GetWindowDrawList()->_ChannelsCurrent;
int prevNumChan = ImGui::GetWindowDrawList()->_ChannelsCount;
ImGui::GetWindowDrawList()->ChannelsMerge();
/* hack end 1 */
ImGui::GetWindowDrawList()->ChannelsSplit(2);
ImGui::GetWindowDrawList()->ChannelsSetCurrent(1);
ImGui::BeginGroup();
if (ImGui::CollapsingHeader("My Group", ImGuiTreeNodeFlags_DefaultOpen)){
ImGui::SliderFloat("val1", &myVal[0], 0, 1);
ImGui::SliderFloat("val2", &myVal[1], 0, 1);
ImGui::SliderFloat("val3", &myVal[2], 0, 1);
ImGui::SliderFloat("val4", &myVal[3], 0, 1);
}
ImGui::EndGroup();
ImGui::GetWindowDrawList()->ChannelsSetCurrent(0);
ImGui::GetWindowDrawList()->AddRectFilled(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255,0,0,64), 5);
ImGui::GetWindowDrawList()->ChannelsMerge();
/* hack begin 2*/
ImGui::GetWindowDrawList()->ChannelsSplit(prevNumChan);
ImGui::GetWindowDrawList()->ChannelsSetCurrent(pervChan);
/* hack end 2*/
ImGui::NextColumn();
ImGui::Text("col 2");
ImGui::SliderFloat("val1", &myVal[4], 0, 1);
ImGui::SliderFloat("val2", &myVal[5], 0, 1);
ImGui::SliderFloat("val3", &myVal[6], 0, 1);
ImGui::SliderFloat("val4", &myVal[7], 0, 1);
ImGui::Columns(1);
ImGui::End(); //////////////////////////////////////////////////////////////////////////////////
Yes, this cannot be used to recurse unfortunately.
If what you are trying to render is only a background (a rectangle) there is a "simpler" workaround. Since the number of vertices is known and small, you could render the background with a dummy color e.g. IM_COL32_WHITE and then recolorize the vertices after the fact.
You'll keep the record the value of draw_list->VtxBuffer.Size before and after your background render call, from there so you rewrite the vertices.
See for example what those functions are doing:
// Shade functions (write over already created vertices)
void ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);
void ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp);
To facilitate this we could add a ShadeVertsRecolorize() function as well, but its implementation should be easy. Note that they are functions in imgui_internal.h and I expect in the future to change their signature to use offset/indices instead of pointers (the reason being that in order to support alternative implementations of ImDrawList getting those pointers out would be better).
@armadillu Any update on this?
Is there any reason you can't use the technique I described to overwrite vertices after the fact? I'd be happy to introduce dedicated ShadeVertsXXX helpers for that purpose.
oh hey sorry, I ended up not needing columns so I didn't dig any more into this. I totally get your solution though, and seems it would have solved my case. Thanks!
Most helpful comment
oh hey sorry, I ended up not needing columns so I didn't dig any more into this. I totally get your solution though, and seems it would have solved my case. Thanks!