Skip to content

Instantly share code, notes, and snippets.

@Folling
Last active May 17, 2024 01:38
Show Gist options
  • Save Folling/44f7682d9fd6a6c846574e336192a66a to your computer and use it in GitHub Desktop.
Save Folling/44f7682d9fd6a6c846574e336192a66a to your computer and use it in GitHub Desktop.

Important Note - Read before continuing!

This solution works right now. It does the job, it does it well. But it is not a good solution. Dear ImGui's layouting capabilities are rather lackluster right now and they will definitely change in the future. So use this if you must, but don't let this creep into your mind as the right thing to do!

Overview

As a default, Dear ImGui aligns all its widgets towards the top left, adding a newline with most added widgets. Sometimes however, you want one or multiple widgets to be centered, right-aligned, or on the bottom right of a window. This is what we'll cover in this part of the series.

Relevant Functions

Aligning things in Dear ImGui can be done in a multitude of ways. The ones you should and will use are:

  1. SameLine - Positions a widget to the right of the previous widget
  2. SetCursorPos (and its affiliates) - Positions a widget at an arbitrary position

Often we'll also need to know how much space we're working with, or where we currently are. For this the following functions can be useful:

  1. GetCursorPos - Obtains the position for where the next widget would be drawn.
  2. GetContentRegionAvail - Obtains the amount of space we have left in the window, accounting for window-padding and the already used space.
  3. GetContentRegionMax - Obtains the content size of the current window.
  4. CalcItemSize - Calculates the size of a specific item, useful to use align widgets.
  5. CalcTextSize - Calculates the size of a specific piece of text, useful to align text

Examples

The general idea is that we can tell Dear ImGui where it should draw a widget using SetCursorPos*.

Finding that position requires a bit of maths, but once you have that it's trivial.

Let's demonstrate how to centre a button:

if(ImGui::Begin("Alignment Tutorial")) {
    ImVec2 button_size = ImVec2{150, 0};

    // obtain width of window
    float width = ImGui::GetWindowSize().x;

    // figure out where we need to move the button to. It's good if you understand why this formula works!
    float centre_position_for_button = (width - button_size.x) / 2;

    // tell Dear ImGui to render the button at the current y pos, but with the new x pos
    ImGui::SetCursorPosX(centre_position_for_button);

    ImGui::Button("Hello!", button_size);
}
ImGui::End();

This will result in:

alignment preview

Note that we use GetWindowSize. This step is crucial to make sure that the button will stay centred even if the window is resized! Using hardcoded numbers will not achieve that effect.


This demonstrates how to centre the button horizontally. You can use the same logic to centre it vertically:

if(ImGui::Begin("Alignment Tutorial 2")) {
    // note that 0 tells Dear ImGui "just use the default"
    ImVec2 button_size = ImGui::CalcItemSize(ImVec2{150, 0}, 0.0f, 0.0f);

    // obtain size of window
    ImVec2 avail = ImGui::GetWindowSize();

    // calculate centre of window for button. I recommend trying to figure out why this works!
    ImVec2 centre_position_for_button{
        (avail.x - button_size.x) / 2,
        (avail.y - button_size.y) / 2
    };

    // tell Dear ImGui to render the button at the new pos
    ImGui::SetCursorPos(centre_position_for_button);

    ImGui::Button("Hello!", button_size);
}
ImGui::End();

Which results in something like this:

alignment preview 2


What if you wanted to have multiple widgets in one line? It's tedious to always calculate the y coordinate. Fret not! SameLine comes to the rescue. It automatically positions a widget to the right of the previous widget, taking spacing into account:

if(ImGui::Begin("Alignment Tutorial 3")) {
    // note that 0 tells Dear ImGui "just use the default"
    ImVec2 button_size = ImGui::CalcItemSize(ImVec2{150, 0}, 0.0f, 0.0f);

    // obtain size of window
    ImVec2 avail = ImGui::GetWindowSize();

    // calculate centre of window for button. I recommend trying to figure out why this works!
    ImVec2 centre_position_for_button{
        // we have two buttons, so twice the size - and we need to account for the spacing in the middle
        (avail.x - button_size.x * 2 - ImGui::GetStyle().ItemSpacing.x) / 2,
        (avail.y - button_size.y) / 2
    };

    // tell Dear ImGui to render the button at the new pos
    ImGui::SetCursorPos(centre_position_for_button);

    ImGui::Button("Hello", button_size);

    // tell Dear ImGui to put the new widget directly to the right of the previous one
    ImGui::SameLine();

    ImGui::Button("World!", button_size);
}
ImGui::End();

Which will result in:

alignment preview 3

Exercises

To hammer down this knowledge, try to recreate the following things:

  1. Have a button where the user can use the arrow keys to change its alignment. All the way from top left, to bottom right
  2. Recreate the button laoyut of a classic save dialog box
@DanielGibson
Copy link

Helpful article, but all the image links in the post are dead

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