Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Horizontal layout #97

Open
emilk opened this issue Dec 12, 2014 · 21 comments
Open

Feature request: Horizontal layout #97

emilk opened this issue Dec 12, 2014 · 21 comments

Comments

@emilk
Copy link

emilk commented Dec 12, 2014

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
Copy link
Owner

ocornut commented Dec 12, 2014

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

  • Horizontal layout, contiguous (optional spacing override)
  • Horizontal layout, evenly spaced (given width or count)
  • Grid layout
  • Vertical layout for consistency could have the same options as horizontal

Notes

  • For the sake of keeping the API terse/optimal it would probably be exposed as different entry points.
  • Can't decide if the functions could be called Push/Pop or Begin/End. Push/Pop is more in line with the current uses. We can have a generic ImGui::PopLayout() function as well.
  • ImGui::PushLayoutHorizontal() makes more sense than ImGui::PushHorizontalLayout() ? in term of categorizing by family, getting completion on IDE, etc.
  • I don't really fancy such a long function name for such as a common feature but cannot find a better one yet.
  • Could have simple "setter" for cases where the code is trivial, to shorten use, so something like ImGui::LayoutHorizontal() since each window will have its stack.

Thanks for the suggestion!

@ocornut
Copy link
Owner

ocornut commented Dec 12, 2014

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

@ocornut
Copy link
Owner

ocornut commented Dec 12, 2014

Could also skip on the Layout word. ?

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

@ocornut
Copy link
Owner

ocornut commented Dec 12, 2014

And add ImGui::NextLine() as well.

@emilk
Copy link
Author

emilk commented Dec 12, 2014

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
Copy link
Owner

ocornut commented Dec 13, 2014

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
Copy link
Owner

ocornut commented Dec 13, 2014

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
Copy link

dkrikun commented Feb 6, 2015

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

@DomGries
Copy link
Contributor

DomGries commented Jun 30, 2016

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
Copy link
Contributor

thedmd commented Jul 22, 2016

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
Copy link

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

@thedmd
Copy link
Contributor

thedmd commented Dec 20, 2021

What's wrong with Stack Layout? #846?

@mnesarco
Copy link

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

@thedmd
Copy link
Contributor

thedmd commented Dec 21, 2021

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. (#846 (comment)).

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

@caxapexac
Copy link

What's wrong with Stack Layout? #846?

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

@caxapexac
Copy link

caxapexac commented Dec 21, 2021

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
Copy link

Any updates on this?

@MohammadMDSA
Copy link

It's taking ages 😂

@Ou7law007
Copy link

One day...

@GabrielJadderson
Copy link

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
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests