I wonder why there is so little support for "native" std::string in imgui. As far as I understood it is meant to be used with c++ (which minimal version, c++11?). Are you interested in a pull request for imgui to support overloads like this (where appropriate):
IMGUI_API bool Combo(const char* label, int* current_item, const std::vector<std::string>& items, int height_in_items = -1);
Similar overloads for ListBox. If you are interested I will try to add them later this week.
For compatibility with most platforms the minimal version is way below C++11. I know it works with VS2008 at least.
Some reasons are:
A) Including or merely referring to std::string would lose a lot of users.
B) std::string are generally inefficient, if you were to casually use them everywhere to create throw-away content for UI traversal it would have performance cost, therefore I can't casually encourage it.
C) Combo already takes a function pointer, so you can implement this helper in 1 line by making an "adapter". It may be worth adding this line in the comments.
bool Combo(const char* label, int* current_item, const std::vector<std::string>& items,, int items_count, int height_in_items = -1)
{
return Combo(label, current_item, [](void* data, int idx, const char** out_text) { *out_text = ((const std::vector<std::string>*)data)[idx].c_str(); return true; }, (void*)&items, items_count, height_in_items);
}
Done. Because ImGui is a namespace you can declare this in your own code as well.
A) Is unfortunately a total deal breaker for so many people that it is enough of a reason to keep imgui totally std:: free.
or use
IMGUI_API bool Combo(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
Combo("label", ¤t,
[](void* vec, int idx, const char** out_text){
std::vector<std::string>* vector = reinterpret_cast<std::vector<std::string>*>(vec)
if(idx < 0 || idx >= vector ->size())return false;
out_text* = vector->at(idx).c_str();
return true;
}, reinterpret_cast<void*>(&str_vector), str_vector.size());
Thanks for your code, guys.
@ocornut, do you think it'll be worth to create "Using ImGui with STL / Modern C++" wiki page which will list some examples such as this, so it would be easier for users to find?
Yes that would be good, I have it in my list of things to do. I will also add a FAQ entry referring to this wiki page.
Potentially adding a "wrapping" header file could be a fair compromise. #include "imgui_stl" that includes imgui.h but would add on modern c++ features. This is very similar to what cppformat (or whatever it's called now) does.
Support for std::string, containers, lambdas, etc. would be in imgui_stl.h and it wouldn't have to have any cost to those who didn't include it and imgui.h wouldn't have to change at all. It could likely be a pure header addition to get rid of any imgui-compile-time complications.
@xaxxon It would be nice. The way I hope imgui evolve is that we can have a repo with standalone extra bits of code and can provide those things. If you want to build imgui_stl.h feel free to do so :)
I don't however think it is that beneficial since there's so many combination of data structures and strings and I'd personally just encourage people to make their own helper. The only thing worse than people creating a temporary array of char* is people creating a temporary array of string. You should access data within your instance and not copy it around too much.
Adding info to this old thread:
Since 1.53 you can use the BeginCombo(), EndCombo() API to implement combo boxes with any contents, so the iteration is on the user side and iterating e.g. vector<string> isn't a problem.
B) std::string are generally inefficient, if you were to casually use them everywhere to create throw-away content for UI traversal it would have performance cost, therefore I can't casually encourage it.
Just as a note, with modern move semantics then using std::string properly can often be far more efficient than about any other model.
if you have a char *, making a std::string requires allocating memory. a string_view would be a much better option, but there are challenges associated with that, as well - like when you have a char* and don't care about how long it is but have to compute it for creation of a string_view because calling .length() must be O(1).
if you have a char *
If you are in C++-land you often don't just have a char *, sometimes a const char * and depending on the string implementation that might not copy it either if it is a literal. String view's are nice but require even newer versions of C++ (definitely opt for them if available though).
but going for cpp support the first step IMO should be to allow passing a capturing lambda and let the user do away with the context pointer:
template<F> IMGUI_API bool Combo_lambda(const char* label, int* current_item, F items_getter, int items_count, int height_in_items = -1){
return Combo(label, current_item,
[](void* data, int idx, const char** out_text){
return (*(F*)data)(idx, out_text);
}, &items_getter, items_count, height_in_items );
}
Combo_lambda("label", ¤t,
[&str_vector](void* vec, int idx, const char** out_text){
if(idx < 0 || idx >= str_vector.size())return false;
out_text* = str_vector.at(idx).c_str();
return true;
}, str_vector.size());
The whole purpose of my post was to state that this is unnecessary, as the item iteration can now be made by the user. So any wrapper is fine in user land.
Most helpful comment
or use