0

I need to be able to use ImGui textboxes, however they don't take const char* or std::string so I need to convert a string to a char array. The problem with this is, however, that I need my char array to be the same size as the string (+1). I get an error saying it needs to be constant value in declaration but I need to be able to access the string's size and make a variable that holds that value as constant. Is this possible? Here is the code:

static std::string text = "";
static bool read_only = false;
char txt[text.size() + 1] = text;
            

ImGui::Begin("Window");

ImGui::InputTextMultiline("Textbox", txt, IM_ARRAYSIZE(txt), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0));

ImGui::End();
         

The format for the ImGui::InputTextMultiline is this:

bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0,0), ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL)

Edit: The textbox needs to be arbitrary size and not limited by a static const value at compile time, rather a dynamic size such that strings are aswell.

  • Can you link the documentation to `ImGui` please so we can see its limitations? Also show code that indicates how you want to use this function. – JohnFilleau Feb 09 '21 at 02:03
  • If you absolutely need a dynamically-sized `char *`, I'd make a `std::vector` of an appropriate size and use [`std::vector::data`](https://en.cppreference.com/w/cpp/container/vector/data) to get the `char *`. If you're in a small function and are careful, you might even use `new` and `delete`. – JohnFilleau Feb 09 '21 at 02:07
  • But more information about the function you're trying to use might yield a more obvious and clean solution. – JohnFilleau Feb 09 '21 at 02:07
  • 2
    `std::string::data` could also be useful if your compiler supports C++17 and your organization will allow it. – user4581301 Feb 09 '21 at 02:08
  • Or you can allocate a buffer large enough that you're certain it will never overflow. And then check to make sure it is big enough, even though you're sure. – JohnFilleau Feb 09 '21 at 02:09
  • And yes, [in Standard C++ the array dimensions must be compile-time constants](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard). You aren't getting that behaviour at runtime. – user4581301 Feb 09 '21 at 02:11
  • 1
    c++20 has constexpr strings so you can just use the `.data()` to get a ptr to a run time const char*. They are also terminated with an extra 0 so compatible with c char strings. – doug Feb 09 '21 at 02:15
  • https://en.cppreference.com/w/cpp/string/basic_string/data – doug Feb 09 '21 at 02:16
  • @user4581301 I'm not sure I understand how to use `std::string::data` in my example –  Feb 09 '21 at 02:17
  • @JohnFilleau with the `std::vector::data` would I even use strings? –  Feb 09 '21 at 02:18
  • @JohnFilleau the problem is though that the contents are modified within the `InputTextMultiline` function –  Feb 09 '21 at 02:19
  • @user4581301 ok I got that working, however it only allows at max a 7 character wide text input. I need a dynamically sized one instead. –  Feb 09 '21 at 02:21
  • 1
    To be honest, it's close to pointless in this case. You make a string, resize the string to an appropriate length, then pass the pointer from `data` an the length into `InputTextMultiline`. when done, you find where the null is and resize the string back to the length used by the string. I misunderstood what a textbox is in this context. It's an input widget, not an output widget. – user4581301 Feb 09 '21 at 02:21
  • That's where `bufsize` comes in. You pass that so the function knows how much space it can play with. I'd go with a local buffer of known size, honestly. That's the canonical way to handle something like this. – JohnFilleau Feb 09 '21 at 02:21
  • I guess the big question is are you using this to display information or get information. If display only, you're probably using the wrong widget and since I don't know ImGui , I'm not able to tell you what you should use instead. – user4581301 Feb 09 '21 at 02:24
  • If you want to get arbitrary length data from the text box, you definitely need to find a different widget. This one can't do what you want. – user4581301 Feb 09 '21 at 02:25
  • @JohnFilleau that worked with the example using `std::string::data` however the actual contents of the string aren't being modified. Is there any way to fix this/ –  Feb 09 '21 at 02:26
  • @user4581301 Can't I just have a temporary char array that I pass in then reassign the string to it and repeat over and over? –  Feb 09 '21 at 02:26
  • If you try to use `std::string::data` without resizing the string to an appropriately large size, you'll run into trouble. If you have nothing in your string, then `string::size` returns 0, and your function call shouldn't allow you to input anything. – JohnFilleau Feb 09 '21 at 02:28
  • @JohnFilleau yes but I specify `std::string::size + 1` that way it will always be able to take 1 more character –  Feb 09 '21 at 02:30
  • You can, but will that do what you want it to do? How do you intend to use this input box? What do you want to get out of it? You should add the use case to the question so folks familiar with ImGui can make suggestions on how to better use `InputTextMultiline` or suggest alternatives. – user4581301 Feb 09 '21 at 02:31
  • Ok ill add to it. I need it to be arbitrary length though, ie, not specified size of characters, can continue forever –  Feb 09 '21 at 02:32
  • It can't continue forever. It's bounded by the maximum value of `std::size_t`, which is likely 2^64 - 1 for you. – JohnFilleau Feb 09 '21 at 02:35
  • I mean, that'll do me just fine :) @JohnFilleau –  Feb 09 '21 at 02:37

1 Answers1

0

Use a local char buffer to accomplish what you want. There's no OS call to allocate memory, and you should have an idea of what you want your maximum allowable input to be.

This function doesn't really do anything. After you get the input, you'll need to copy the data into a std::string or something else to do stuff with it.

std::string get_text_input(std::size_t arbitrary_size) {
    char* buf = new char[arbitrary_size];

    ImGui::Begin("Window");

    ImGui::InputTextMultiline("Textbox", buf, arbitrary_size, ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0));

    ImGui::End();

    std::string ret(buf);

    delete[] buf;

    return ret;
}

Disregard the above. You should use this function signature: https://github.com/ocornut/imgui/blob/01cc6660395032714e7a991eba679a9c69b00c5b/misc/cpp/imgui_stdlib.cpp#L54

bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)

JohnFilleau
  • 4,045
  • 1
  • 15
  • 22
  • I need it to be an arbitrary length textbox. That is why I can't specify a compile time value to my `char buf[]` –  Feb 09 '21 at 02:29
  • Will that have a memory leak with `new`? Or will it be okay to delete when I am done with `ImGui::End();` –  Feb 09 '21 at 02:33
  • I would, which is why I juuuuust fixed it. – JohnFilleau Feb 09 '21 at 02:34
  • The text now doesn't appear on the screen/isn't being rendered. Is there any way I can have the contents of the `InputTextMultiline` stored as a string and have some manipulations to get that to work.? –  Feb 09 '21 at 02:37
  • What does "the contents of the InputTextMultiline" mean? – JohnFilleau Feb 09 '21 at 02:39
  • The string of text that it displays on the screen –  Feb 09 '21 at 02:40
  • 1
    *"There's no OS call to allocate memory,"* that is at-best optimistic speculation. You have no idea what `operator new` will do. It is implementation-defined in its internals. Further, there is nothing in this code that [`std::vector`](https://pastebin.com/n8cHN3Kx) could *not* do, and add the benefit of being exception-safe and not leak memory in the unfortunate consideration of catastrophe. There is literally *no* instance in modern C++ to use `operator new` and `operator delete` for *anything* outside of placement-new scenarios. – WhozCraig Feb 09 '21 at 02:54
  • @JohnFilleau I added the header and cpp files of that link to the project. But when I go to call the function it doesn't update it to the `std::string* ` value. Additionally I tried to copy the implementation of the declaration where they cast it to a `char*` but the length made it to about 12 and then didn't let me add more –  Feb 09 '21 at 02:55
  • @WhozCraig feel free to edit the answer or add your own. Collaboration, etc. – JohnFilleau Feb 09 '21 at 03:01