Imgui: ChannelsSplit() can't be used with columns

Created on 30 Jul 2018  路  4Comments  路  Source: ocornut/imgui

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(); //////////////////////////////////////////////////////////////////////////////////
drawindrawlist

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!

All 4 comments

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mkanakis picture mkanakis  路  3Comments

KaungZawHtet picture KaungZawHtet  路  3Comments

spaderthomas picture spaderthomas  路  3Comments

Folling picture Folling  路  3Comments

bizehao picture bizehao  路  3Comments