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

How do I align multiline text in the center of a button? #6164

Closed
marzRX opened this issue Feb 14, 2023 · 12 comments
Closed

How do I align multiline text in the center of a button? #6164

marzRX opened this issue Feb 14, 2023 · 12 comments

Comments

@marzRX
Copy link

marzRX commented Feb 14, 2023

Version/Branch of Dear ImGui:
Version: 1.89
Branch: master

Back-end/Renderer/Compiler/OS
Back-end: GLFW + OpenGL3
Compiler: g++(MinGW)
OS: windows7

My Issue/Question:
I want to align text with an icon font to the center of a button.
If I specify (0.5, 0.5) for ButtonTextAlign, I get the following.
imgui_buttontext_alignment

What I am expecting is the following result. (Edited by Photoshop.)
imgui_buttontext_aligncenter

Code:
ImGuiStyle& style = ImGui::GetStyle();
style.ButtonTextAlign = ImVec2(0.5, 0.5);
ImGui::Begin("Button with ICON");
{
ImGui::Button(ICON_FA_WRENCH "\nproperty", ImVec2(120.0, 0.0)); ImGui::SameLine();
ImGui::Button("1st line\n2nd", ImVec2(120.0, 0.0)); ImGui::SameLine();
ImGui::Button(ICON_FA_INFO "\ninfo", ImVec2(120.0, 0.0));
}
ImGui::End();

Is there a parameter that would allow me to achieve this?

@ocornut
Copy link
Owner

ocornut commented Feb 14, 2023

It is currently not possible. I am expecting that in a few version this will become possible.

(You can workaround this by rendering text manually over the buttom, if you think this is worth the effort)

@marzRX
Copy link
Author

marzRX commented Feb 14, 2023

Thank you for the reply. I understand that it is currently not possible.

Are you suggesting that I should run ButtonEX() up to RenderFrame() and call SetCursorPos() and Text()?

@ocornut
Copy link
Owner

ocornut commented Feb 14, 2023

Use Button() with a non-visible label “##identifier” then ImDrawList::AddText() call to overlay the text.

@marzRX
Copy link
Author

marzRX commented Feb 14, 2023

Thank you very much. I gonna try that. : )

@marzRX
Copy link
Author

marzRX commented Feb 15, 2023

Thank you. I am now able to do what I was intended to do.

If it helps anyone who wants to do the same.

#include <string>
#include <vector>

using namespace std;

// Separate strings with linefeed
void breakApartLF(string line, vector<string> *v)
{
  int pos;
  string delimiter="\n";

  pos = line.find(delimiter);
  while (pos != -1) {
    v->push_back(line.substr(0, pos));
    line.erase(0, pos+1);

    pos = line.find(delimiter);
  }
  v->push_back(line);
}

bool ButtonCenter(const char* label, const ImVec2& size_arg)
{
  ImGuiButtonFlags flags = ImGuiButtonFlags_None;
  ImGuiWindow* window = ImGui::GetCurrentWindow();
  if (window->SkipItems)
    return false;

  ImGuiContext& g = *GImGui;
  const ImGuiStyle& style = g.Style;
  const ImGuiID id = window->GetID(label);
  const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);

  ImVec2 pos = window->DC.CursorPos;
  if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
    pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;
  ImVec2 size = ImGui::CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);

  ImVec2 pos2;
  pos2.x = pos.x+size.x;
  pos2.y = pos.y+size.y;
  const ImRect bb(pos, pos2);
//  const ImRect bb(pos, pos + size);
  ImGui::ItemSize(size, style.FramePadding.y);
  if (!ImGui::ItemAdd(bb, id))
    return false;

  if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
    flags |= ImGuiButtonFlags_Repeat;

  bool hovered, held;
  bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags);

  // Render
  const ImU32 col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
  ImGui::RenderNavHighlight(bb, id);
  ImGui::RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
  float font_height = g.FontSize;

  vector<string> list;
  breakApartLF(label, &list);

  ImVec2 targetline_size; // Font size for each line [pixel]
  ImVec2 text_start; // Character start position for each line
  int offset_x, offset_y; // Offset from top left of button
  ImDrawList * DrawList = ImGui::GetWindowDrawList();
  ImVec2 padding_regular = g.Style.TouchExtraPadding;
  ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular;

  for (int i=0; i<list.size(); i++) {
    targetline_size = ImGui::CalcTextSize(list[i].c_str(), NULL, true);
    offset_x = (size.x - targetline_size.x) / 2.0;
    if (targetline_size.y != 0) {
      offset_y = targetline_size.y * i + padding_for_resize.y;
    } else {
      offset_y = font_height * i + padding_for_resize.y;
    }
    text_start.x = bb.Min.x + offset_x;
    text_start.y = bb.Min.y + offset_y;
    DrawList->AddText(text_start, ImGui::GetColorU32(ImGuiCol_Text), list[i].c_str());
  }

/*
    if (g.LogEnabled)
        LogSetNextTextDecoration("[", "]");
    RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);

    // Automatically close popups
    //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
    //    CloseCurrentPopup();

    IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
*/
    return pressed;
}

You are welcome to point out what is wrong with the code.

@ocornut
Copy link
Owner

ocornut commented Feb 15, 2023

You shouldn’t need to copy all that code.

You can do:

PushID(label);
label_size = CalcTextSize(…);
bool ret = ButtonEx(“”, label_size + style.FramePadding * 2);
// render your text here
PopID()
return ret;

@marzRX
Copy link
Author

marzRX commented Feb 15, 2023

I think I understand your point correctly.
I just thought this would be more convenient for me when displaying a lot of buttons.

  ButtonCenter(ICON_FA_INFO "\ninfo", ImVec2(120.0, 0.0)); ImGui::SameLine();
  ButtonCenter(ICON_FA_INFO "\n情報", ImVec2(120.0, 0.0)); ImGui::SameLine();
  ButtonCenter(ICON_FA_TRASH_ALT "\nゴミ箱", ImVec2(120.0, 0.0));

I am happy with what I wanted to do.

What I'm wondering is that I get an error when I try to add two IVec2's together in my code.
I didn't want to ask the question because it would reveal a little bit of my ignorance.

@ocornut
Copy link
Owner

ocornut commented Feb 15, 2023

I fully agree it's neater that you wrap this in a helper ButtonCenter() function! I am saying in theory that function could be smaller since you can call ButtonEx() from it if you use that PushID(label); ButtonEx(""); PopID(); sequence.

What I'm wondering is that I get an error when I try to add two IVec2's together in my code.

No worry, it is a common question (we should probably add it in the FAQ).
See https://github.com/ocornut/imgui/blob/master/imgui_internal.h:

// To implement maths operators for ImVec2 (disabled by default to not conflict with using IM_VEC2_CLASS_EXTRA with your own math types+operators), use:
/*
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui_internal.h"
*/

The reason we don't expose math operators in imgui.h is that they would conflict with user's/engine's own math operators if IM_VEC2_CLASS_EXTRA is being used:
https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-can-i-use-my-own-math-types-instead-of-imvec2imvec4

I'm thinking it may be neater if we allowed imgui.h to optionally define math operators as a helper for people who don't have their own.

@marzRX
Copy link
Author

marzRX commented Feb 15, 2023

After defining IMGUI_DEFINE_MATH_OPERATORS, IVec2 can now be added together.
I also understood that IM_VEC2_CLASS_EXTRA provides a mechanism to combine with external math libraries.

I am going to try to do this with the following link. Thank you.
Integrate glm/nap types with Dear ImGui

@marzRX marzRX closed this as completed Feb 15, 2023
ocornut added a commit that referenced this issue Feb 15, 2023
…ATH_OPERATORS) implementation from imgui_internal.h in imgui.h. (#6164, #6137, #5966, #2832)
@ocornut
Copy link
Owner

ocornut commented Feb 15, 2023

This discussion prompted me to move this opt-in compile-time feature from imgui_internal.h to imgui,h:
a1b8457

And it has been added to the FAQ:
https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-can-i-use-maths-operators-with-imvec2

@WyattRichartz
Copy link

Just came across this. I am very new to the ImGui library and I just ran into this issue and this post helped me out tremendously, both with fixing the issue itself and learning a bit more about how the text alignment of the library works. I just wanted to share my appreciation for posting this publicly, thanks a ton!

@marzRX
Copy link
Author

marzRX commented Feb 21, 2024

I'm glad to hear it was helpful. :)

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

3 participants