ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
57.96k stars 9.93k forks source link

Feature request: Horizontal layout #97

Open emilk opened 9 years ago

emilk commented 9 years ago

The only way I've found to do horizontal layout in ImGui is to call SameLine() in between widgets that should go on the same line. This is problematic when the widgets are painted by some other code. In particular, I want to lay out an unknown number of Text:s horizontally on the same line.

May I suggest adding something like:

ImGUI::PushHorizontalLayout(int spacing_w = -1);  // All subsequent widgets will be positioned to the right of the previous one
ImGUI::PopHorizontalLayout();                     // Ends the line
ocornut commented 9 years ago

Yes!

The reason I haven't added the simple version yet (like your suggested API) is that I wanted to spend more time considering the layout problem holistically.

We'd probably want

Notes

Thanks for the suggestion!

ocornut commented 9 years ago

But you are right, a simple helper would be welcome asap.

ocornut commented 9 years ago

Could also skip on the Layout word. ?

Horizontal() / BeginHorizontal() / EndHorizontal() Vertical() / BeginVertical() / EndVertical()

ocornut commented 9 years ago

And add ImGui::NextLine() as well.

emilk commented 9 years ago

Yeah, for now I've created my own NextLine based on Separator - that kind of works =)

I feel push/pop is more descriptive iff nesting is supported. I'm all for skipping the "Layout" part, i.e. PushHorizontal/PopHorizontal.

PushHorizontal(); Text("a"); Text("b"); PushVertical(); Text("c"); Text("d"); PopVertical(); PopHorizontal();

->

a b c
    d

Something like that?

ocornut commented 9 years ago

But:

Text("a"); SameLine(); Text("b"); Text("c"); Text("d");

Currently becomes:

  a b
  c
  d

So starting a vertical layout should "lock" the X current coordinate? Which is what happens with your example. In which case how to do achieve the layout above with the Push/Pop system?

PushHorizontal(); Text("a"); Text("b"); PopHorizontal(); 
NextLine(); // Could be implicit ?
Text("c");
Text("d");

If locking is done on "pushing" the vertical layout and not "popping" then we can't have Horizontal() / Vertical().

Horizontal(); Text("a"); Text("b"); Vertical(); Text("c"); Text("d"); 

Does that become the layout in your example or in mine? Gets a bit confusing.

So my proposal is that all those gives the same output:

PushHorizontal(); Text("a"); Text("b"); PushVertical(); Text("c"); Text("d"); PopVertical(); PopHorizontal();
PushHorizontal(); Text("a"); Text("b"); PopHorizontal(); Text("c"); Text("d"); 
Horizontal(); Text("a"); Text("b"); Vertical(); Text("c"); Text("d");

That is:

  a b
  c
  d

So there's less stored state.

Now if we want to implement your layout example (which is more of a rare case) we can have a way to set the value internally called "ColumnsStartX" (those variables can be cleaned up/renamed before being publicly exposed).

ImGui::SetColumnStartX(float x)
// this
ImGui::PushVertical(bool use_pos_x_as_column_start = false);
ImGui::Vertical(bool use_pos_x_as_column_start = false);
// or that
ImGui::PushVertical(float column_x = 0.0f);  // default left side. passing -1 uses current cursor x
ImGui::Vertical(float column_x = 0.0f);  // default left side. passing -1 uses current cursor x

Passing a float is more flexible but the difference between 0.0f (left side) and -1.0f (current cursor x) may be a bit arbitrary ? I guess you can always do ImGui::Vertical(ImGui::GetCursorPosX()); as well.

Does it makes sense?

ocornut commented 9 years ago

Also - the devil is in the details - we would probably want to add WindowPadding.x to the provided offset_x. Which becomes a problem because:

  ImGui::Vertical(0.0f);             // >> 0.0f + WIndowPadding.x
  ImGui::Vertical(GetCursorPosX()); // >> GetCursorPosX() + WindowPadding.x // Undesireable, cursor pos already include the padding.

We could treat 0.0f as a special case but that would be dodgy.

So a more consistent solution would be:

 column_x < 0.0f    (default value to all calls) gets turned into WindowPadding.x
 column_x > 0.0f    untouched

But then to implement your example you would need to call GetCursorPosX() and we lose the "lock current x position" shortcut.

dkrikun commented 9 years ago

I think Horizontal()/Vertical() plus PushCurrentLayout() can simplify things: wanna change layout? -- change, wanna save? -- push/pop.

DomGries commented 8 years ago

Awesome library but I really hope this gets worked on soon as the current solution to use ImGui::CalcTextSize is non-ideal for performance since this gets then get called twice (since it is also used the control like the text box itself). This is my code just to display a centered text on the screen which is twice as big as the default size. Btw any way to SetNextWindowFontScale since we are supposed to use SetNextWindowSize and the like which doesn't work properly if you change the font scale?

const ImGuiIO& guiIO = ImGui::GetIO();

const static char* titleWindowTitle = "title";
ImGui::Begin(titleWindowTitle, nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);

const static char* title = "Centered Title";
ImVec2 textSize = ImGui::CalcTextSize(title);
ImVec2 windowSize = ImVec2(textSize.x + Constants::UiPadding * 2.f, textSize.y + Constants::UiPadding * 2.f);

ImGui::SetWindowPos(ImVec2((guiIO.DisplaySize.x - windowSize.x) * 0.5f, (guiIO.DisplaySize.y - windowSize.y) * 0.5f));
ImGui::SetWindowSize(windowSize);

ImGui::SetWindowFontScale(2.f);

ImGui::TextUnformatted(title);
ImGui::End();
thedmd commented 7 years ago

There is something for me. Basic implementation of layouts in form of BeginHorizontal/EndHorizontal.

            ImGui::BeginHorizontal("example_h1", spanToWindow ? bounds : ImVec2(0, 0));
                ImGui::TextUnformatted("Left");
                ImGui::Spring(middleWeight);
                ImGui::TextUnformatted("Middle");
                ImGui::Spring(1.0f - middleWeight);
                ImGui::TextUnformatted("Right");
            ImGui::EndHorizontal();

It is rough around the edges so please give me a feedback how it can be improved.

stack_layout

caxapexac commented 2 years ago

It's been 7 years already, any updates on builtin layouts? Or maybe any well-maintained addon?

thedmd commented 2 years ago

What's wrong with Stack Layout? #846?

mnesarco commented 2 years ago

@thedmd the only thing wrong with StackLayout is that it is not merged :D

thedmd commented 2 years ago

In some time I think a change can be proposed to allow other layout engines too. Truth is Stack Layouts are one of the possible solutions. Grids, forms (labels on the left anyone?), overflow layouts are examples of alternatives better suited for their respective use cases.

As for today few small modifications in ImGui are necessary to make custom layout code possible. (https://github.com/ocornut/imgui/pull/846#issuecomment-986006070).

There is a branch where Stack Layout code is moved to eventually became a plugin/extension to ImGui feature/layout-external.

caxapexac commented 2 years ago

What's wrong with Stack Layout? #846?

It's exactly what I want but It's still not merged( Any ETA?

caxapexac commented 2 years ago

In some time I think a change can be proposed to allow other layout engines too.

Yes importing yoga/flexbox would be a great addition too

joshcamas commented 1 year ago

Any updates on this?

MohammadMDSA commented 1 year ago

It's taking ages 😂

Ou7law007 commented 9 months ago

One day...

GabrielJadderson commented 7 months ago

This works for me

int maxColumns = 10;
ImGui::Columns(maxColumns, "MyLayout", false); 
ImGui::SetColumnWidth(0, 80);
for (int i = 1; i < maxColumns - 1; i++)
{
    ImGui::SetColumnWidth(i, 80);
    ImGui::Text("item");
    ImGui::NextColumn();
}
ImGui::EndColumns();
nikkorejz commented 3 months ago

I'm just in the process of studying, and I'm unlikely to be useful in terms of project development right now. But, if someone decides to improve it, then I suggest considering the implementation https://developer.android.com/reference/android/widget/LinearLayout

I don't mean the code itself, but the capabilities of this Layout, which has been built into the Android OS since the first version. What would be cool to see: weightSum, orientation and gravity setup