Hi
is it possible to add splitter between 2 widgets ? . if no then i hope you consider it as a todo :) , because changing layout space in realtime is really good thing .
EDITED 2018: If you are stumbling on this thread, read the post at the end of the thread, tl;dr; you can use SplitterBehavior in imgui_internal.h as a helper
There's a Columns() API that does some of that, depending exactly what is your use case and what you are trying to do. Splitter is a rather vague term.
For high-level layout you can possibly get away by implementing cheap splitters yourself:
https://github.com/ocornut/imgui/issues/125#issuecomment-135775009

But yes I agree we need better moveable separator in general.
thanks
yes that https://github.com/ocornut/imgui/issues/125#issuecomment-135775009 what i was aiming for
in the example you provide , some times if i click on the separator it didn't move but the whole window moves instead .
Where are you clicking for it to not work? You can replace InvisibleButton() by Button() to see them.
Oops , seems i was trying with an old version of imgui , now i am switching to 1.45 and it works fine now ;)
many thanks
Reused this idiom in an app. The code is app specific here, we'd want to formalize into an official API call once we can figure out an api to handle n-part splitting.
SetItemAllowOverlap to allow widget to cover the splitter, that also could be exposed in the public API. EDIT This is now a public api.void DrawSplitter(int split_vertically, float thickness, float* size0, float* size1, float min_size0, float min_size1)
{
ImVec2 backup_pos = ImGui::GetCursorPos();
if (split_vertically)
ImGui::SetCursorPosY(backup_pos.y + *size0);
else
ImGui::SetCursorPosX(backup_pos.x + *size0);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0,0,0,0));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0,0,0,0)); // We don't draw while active/pressed because as we move the panes the splitter button will be 1 frame late
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.6f,0.6f,0.6f,0.10f));
ImGui::Button("##Splitter", ImVec2(!split_vertically ? thickness : -1.0f, split_vertically ? thickness : -1.0f));
ImGui::PopStyleColor(3);
ImGui::SetItemAllowOverlap(); // This is to allow having other buttons OVER our splitter.
if (ImGui::IsItemActive())
{
float mouse_delta = split_vertically ? ImGui::GetIO().MouseDelta.y : ImGui::GetIO().MouseDelta.x;
// Minimum pane size
if (mouse_delta < min_size0 - *size0)
mouse_delta = min_size0 - *size0;
if (mouse_delta > *size1 - min_size1)
mouse_delta = *size1 - min_size1;
// Apply resize
*size0 += mouse_delta;
*size1 -= mouse_delta;
}
ImGui::SetCursorPos(backup_pos);
}
Usage
DrawSplitter(); // code above
BeginChild(...); // pass width here
EndChild()
SameLine()
BeglnChild(...); // pass width here
EndChild()

nice. move tutorial will be great!
Hi,
I have try to change the mouse cursor once we are over the split bar, but nothing is changing :
if (GImGui->HoveredIdAllowHoveringOthers && horizontal_splitter)
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
else if (GImGui->HoveredIdAllowHoveringOthers && !horizontal_splitter)
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
else
ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow);
@ghost Sorry I missed this question. Is your binding applying the hardware mouse cursor as requested by ImGui? (by reading GetMouseCursor). ImGui can display a software cursor for you but hardware are much much more pleasant so it is better to avoid them if you can.
FYI
Today I have added a ImGuiButtonFlags_AllowOverlapMode flag to the ButtonEx() function declared in imgui_internal.h. This is useful if you want to create invisible splitter than are using left-over space not used by other widgets, as shown in the bottom splitter in my GIF above.
It previously worked because I was using an alpha of 0.0 for the splitter hovered color, so when hovering a button you wouldn't see that the splitter was actually seeing itself as hovered as well. With that new flag we can now implement a splitter that has a hovered color and still allow for overlapping widgets.
I just modified two lines for correct visual effect:
void Splitter(bool split_vertically, float thickness, float* size0, float* size1, float min_size0, float min_size1, float size = -1);
and
ImGui::Button("##Splitter", ImVec2(!split_vertically ? thickness : size, split_vertically ? thickness : size));
before:

after:

I'm currently working on splitter toward formalizing Docking #351 features.
If you are using the old splitter patterns, here's a little update for the code to handle mouse going out of limits more gracefully.
Replace:
float mouse_delta = split_vertically ? ImGui::GetIO().MouseDelta.y : ImGui::GetIO().MouseDelta.x;
With:
ImVec2 item_bb = ImGui::GetItemRectMin();
float mouse_delta = split_vertically ? (g.IO.MousePos.y - g.ActiveIdClickOffset.y - item_bb.Min.y) : (g.IO.MousePos.x - g.ActiveIdClickOffset.x - item_bb.Min.x);
I will create a helper for it as it is a common pattern for dragging operations.
FYI the pattern above has been reworked and included in imgui.cpp for internal use (via imgui_internal.h), as:
bool SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f);
You can now reproduce the behavior of the function listed above with a smaller function:
EDITED
bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f)
{
using namespace ImGui;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiID id = window->GetID("##Splitter");
ImRect bb;
bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f);
return SplitterBehavior(id, bb, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f);
}
However I don't think that old signature is good, and not including this facade in the public API. I'm working on a better higher-level system. Mostly posting this here for the records.
Test code:
float h = 200;
static float sz1 = 300;
static float sz2 = 300;
Splitter(true, 8.0f, &sz1, &sz2, 8, 8, h);
BeginChild("1", ImVec2(sz1, h), true);
EndChild();
SameLine();
BeginChild("2", ImVec2(sz2, h), true);
EndChild();
@ocornut here,
bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size2));
should be
bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
right? Assuming the first size is the window that comes above.
@nikki93 Correct, I edited my post above. Thanks! (It doesn't affect anything on the git repository as that Splitter() function was just part of my message.)
If you are using SplitterBehavior() from imgui_internal.h, note that I have inverted the 2 first parameters
From
bool ImGui::SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, ...
To
bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ...
Which is more consistent with other internal functions of the same type.
We had a question re the best way to handle nested child Windows using the splitter with regards to Horizontal layout ? Say we are looking at 1 vertical splitter and each vertical half has multiple horiz splitters. We are trying to create the ability to do the layout from config file and have each container area (Child windows that is not visible) have the ability to add multiple panels (Child windows) with possible splitters in them. If we do them one container at time then the draw cursor is not at the appropriate place so the SameLine() call cannot be used. Should we be using SetCursorPos() to position before drawing every container ? Or is there a better way ? Something like a Horizontal layout stack for all subsequent calls that can be popped to bring us back to line we started ie the original child container window pos ??
SplitterVert1()
BeginChild(V0);
SplitterHoriz1()
BeginChild(H1)
EndChild
SplitterHoriz2()
BeginChild(H2)
EndChild
EndChild();
BeginChild(V1)
SplitterHoriz3()
BeginChild(H3)
EndChild()
EndChild(V1)
Hello @turmansky,
I am not sure I understand your question very precisely, but if SetCursorPos() works for you then that's good. However you may want to look at the Docking branch #2109.
Thx. We will take a look at that branch.
The general question is regarding aligning controls horizontally in groups where drawing is per group rather than across the entire window. SetCursorPos seems to help us in these scenarios but were wondering if there were plans for a horizontal layout stack push/ pop like functionality
if there were plans for a horizontal layout stack push/ pop like functionality
Yes will eventually.
Hey, i am using a Binding for ImGui (ImGui.NET), which is the reason why i can't use imgui_internal.h. So i tried implementing the splitter using the original snippet:
private void DrawSplitter(bool split_vertically, float thickness, ref float size0, ref float size1,
float min_size0, float min_size1, float size = -1.0f)
{
var backup_pos = ImGui.GetCursorPos();
if (split_vertically)
ImGui.SetCursorPosY(backup_pos.Y + size0);
else
ImGui.SetCursorPosX(backup_pos.X + size0);
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.6f,0.6f,0.6f,0.1f));
ImGui.Button("##Splitter", new Vector2(split_vertically ? thickness : size, !split_vertically ? thickness : size));
ImGui.PopStyleColor(3);
ImGui.SetItemAllowOverlap(); // This is to allow having other buttons OVER our splitter.
if (ImGui.IsItemActive())
{
float mouse_delta = split_vertically ? ImGui.GetMouseDragDelta().Y : ImGui.GetMouseDragDelta().X;
// Minimum pane size
if (mouse_delta < min_size0 - size0)
mouse_delta = min_size0 - size0;
if (mouse_delta > size1 - min_size1)
mouse_delta = size1 - min_size1;
// Apply resize
size0 += mouse_delta;
size1 -= mouse_delta;
}
ImGui.SetCursorPos(backup_pos);
}
The issue is that the original snippet isn't working at all.
So i wanted to ask how long it'll take the splitter functionality to come into core ImGui.
It鈥檚 already in ImGui as you pointed out :)
Maybe see how your binding could optionally expose/export the internal function(s) you want, otherwise it is probably a small patch to add it yourself?
No ETA for making it in public api yet.
By the way, even though the current function differs from the original snippets, looking at your code it seems like it should work. So that鈥檚 also worth investigating!
Most helpful comment
Reused this idiom in an app. The code is app specific here, we'd want to formalize into an official API call once we can figure out an api to handle n-part splitting.
SetItemAllowOverlapto allow widget to cover the splitter, that also could be exposed in the public API. EDIT This is now a public api.Usage