ocornut / imgui

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

Align Buttons and Textbox? #934

Open skl131313 opened 7 years ago

skl131313 commented 7 years ago

I'm trying to get 3 buttons and a textbox on the same line along with a label. I want the text on the end to be aligned with everything else.

ImGui::Button("first"); ImGui::SameLine();
ImGui::Button("second"); ImGui::SameLine();
ImGui::Button("third"); ImGui::SameLine();
ImGui::InputText("##value", ... , ImGuiInputTextFlags_ReadOnly); ImGui::SameLine();
ImGui::TextUnformatted("name");'

// How it ends up formatted:
// [contents0              ] [ label ]
// [b1] [b2] [b3] [inputText    ] [ label ]
// [contents1              ] [ label ]
ocornut commented 7 years ago

Use PushItemWidth(n); with n being a negative number.

skl131313 commented 7 years ago

How would I calculate the width then? I tried PushItemWidth(-(GetWindowContentRegionWidth() - CalcItemWidth())) but that doesn't seem to take indention into account.

ocornut commented 7 years ago

You don't, -n is the distance you want to be available for labels.

skl131313 commented 7 years ago

I want that distance to be the default, and i only want to set it for this one item. I don't want to change the width for all other items.

PushItemWidth(-(GetWindowContentRegionWidth() - CalcItemWidth()))

Does that except for when indention is used, such as in a tree node.

ocornut commented 7 years ago

Hmm it should be something like that but I'll look in details later. I agree it is an issue that this form of alignment isn't more readily obvious.

colesnicov commented 7 years ago

Hi sprinkle131313,

You solved it?I want to have an alignment button to the right so I tried:

I gained some numbers

int i = ImGui::GetCurrentWindow()->SizeContents.x;

And trying to offset follows

ImGui::Spacing ();
ImGui::SameLine(i - 60.0f);

or this way ImGui::Indent(i - 60.0f); and draw: ImGui::Button("Cancel", ImVec2(60, 30)); Neither of them does not work correctly.

skl131313 commented 7 years ago

I never got it working completely. For your code though I think it's a bit different of a scenario.

Maybe this will help? https://github.com/ocornut/imgui/issues/196

colesnicov commented 7 years ago

yep, I saw it.

English language not learned much, I look at the text and are looking for familiar words :-D. I currently use this:

ImVec2 windowSize = ImGui::GetIO().DisplaySize - ImVec2(50, 60); // My ImGui window as fullscreen - padding (x=50, y=60)
ImVec2 buttonSize(60, 30); // My button size
ImGui::SetCursorPos(windowSize - ImVec2(10, 10) - buttonSize); // Move cursor on needed positions
ImGui::Button("Save", buttonSize))e - ImVec2(10, 10) - buttonSize); // Draw button

but sometimes it does not work properly. Specifically, I'm the one case that still has to remodel, Align button to the right but to me and to each frame in increasing the width and push the more to the right. It looks like a slide animations to hide the buttons: D Total funny ...

Ala google translate..

JaminGrey commented 7 years ago

(I wasn't sure what existing Issue to put this in, or whether I should start a new one about right-alignment)

I have multiple widgets on a line to the left, but I want to switch to a right-alignment on the same line, and have multiple widgets aligned right.

Here is how I currently do it:

const float ItemSpacing = ImGui::GetStyle().ItemSpacing.x;

static float HostButtonWidth = 100.0f; //The 100.0f is just a guess size for the first frame.
float pos = HostButtonWidth + ItemSpacing;
ImGui::SameLine(ImGui::GetWindowWidth() - pos);
if(ImGui::SmallButton("Become host"))
{ ... }
HostButtonWidth = ImGui::GetItemRectSize().x; //Get the actual width for next frame.

static float ClientButtonWidth = 100.0f;
pos += ClientButtonWidth + ItemSpacing;
ImGui::SameLine(ImGui::GetWindowWidth() - pos);
if(ImGui::SmallButton("Connect as client"))
{ ... }
ClientButtonWidth = ImGui::GetItemRectSize().x; //Get the actual width for next frame.

static float LocalButtonWidth = 100.0f;
pos += LocalButtonWidth + ItemSpacing;
ImGui::SameLine(ImGui::GetWindowWidth() - pos);
if(ImGui::SmallButton("Play local"))
{ ... }
LocalButtonWidth = ImGui::GetItemRectSize().x; //Get the actual width for next frame.

Result: imgui right-aligned

This works fine. However, I'd like an API interface like this:

ImGui::Button("..blah..."); //...blah... existing left-aligned widgets.
ImGui::SameLine();
ImGui::Button("..blah 2..."); //Cursor automatically increases by the width of the previous widget.
ImGui::SameLine();

//Reset the cursor to "ImGui::GetWindowWidth()" (or to 0, if ImGui_Alignment_Left).
//Set internal alignment flag.
ImGui::SetAlignment(ImGui_Alignment_Right);

ImGui::Button("..I'm aligned right..."); //Cursor automatically subtracks the width of the previous widget.
ImGui::SameLine();
ImGui::Button("..I'm also aligned right...");

Each call to ImGui::SetAlignment() entirely resets the cursor position (to 0 or the window width, depending on the alignment enum passed in). So doing SetAlignment(right), drawing widgets, SetAlignment(left), drawing widgets, and then SetAlignment(right) does not preserve the previous cursor positions, and will of-course draw over the widgets you originally drew.

Edit: If in a column or child frame, it should right-align to the side of that column/frame. So I guess always just right-align to the end of the current column width, because even child-frames have single-columns unless specified otherwise, I think?

It may also be good to think of a similar syntax for vertical alignment - e.g. drawing buttons pinned to the bottom of the window. How that should or shouldn't interact with automatic window resizing, I haven't a clue (maybe each bottom-aligned new line should add to the total height, just as each top-aligned already does. Swapping back and force between vertical alignments should probably - for simplicity of coding - also just reset the (vertical) cursor position entirely).

Entirely unrelated, but it'd also be nice to have:

PushSameLine();
//...multiple widgets...
PopSameLine();

...where we don't have to call SameLine() between each widget. Requiring SameLine() should still be the default.

ocornut commented 7 years ago

@JaminGrey Thanks for that post. This is something that I've been discussing with someone recently. I think it is worthy of a new thread but fine here as the thread is open. As part of improving layout features support for basic filling from one of 4-way will be desirable.

One thing to consider, is that most of the widgets or usage patterns don't take into consideration that there is a limit, so what do we do when you reach it (e.g. submit too many buttons). We can just a hard clipping line but we need to make sure the implementation doesn't make us end up with too many draw calls.

We could probably do the ground work to expose this internally with at minimum backuping the position on each side, that wouldn't be too hard and probably useful as a start.

Entirely unrelated, but it'd also be nice to have: PushSameLine(); //...multiple widgets... PopSameLine();

This is #97 (oldest open topic?). There is something internally where you can use window->DC.LayoutType = ImGuiLayoutType_Horizontal but it isn't finished or exposed, you can create yourself a helper to handle that stack, or a C++ helper that backups LayoutType, changes it, and restore on destruction.

I would like to introduce some sort of flow layout feature when layout can automatically go to the next line. It's not a very difficult feature per se but it will incur change to the code of every widget. Maybe will do this refactor before the end of year (I actually attempted it doing it four weeks ago, for this and for #395, and run into variety of problems and then I realized it wasn't a half-day refactor, more like a three-days one to do this right).

moebiussurfing commented 1 year ago

Any news on that topic?

Looking for a layout helper to right-align widgets. Or to exclude ImGui::NextLine sometimes depending on window width. (to avoid populate non visible widgets out of the visible right window border, and put them on the next line.)

A found some workaround snippets but nothing serious yet... Also some branches/forks like on here: https://github.com/ocornut/imgui/pull/846