Closed MattBystrin closed 2 years ago
Hello! I will give a more detailed answer tonight.
I was thinking about maybe something like:
auto item_1 = Renderer([] (bool focused) {
if (focused)
return text("> item_1") | bgcolor(Color::Red);
else
return text(" item_1")
})
auto item_2 = Renderer([] (bool focused) {
if (focused)
return text("> item_2") | bgcolor(Color::Blue);
else
return text(" item_2")
})
int selected_item = 0;
auto menu = Container::Vertical({
item_1,
item_2,
&selected_item);
It has some drawback, but you can render anything inside the menu.
Thanks for reply !
Today I came up with 2 possible solutions.
Thirst one is to pass std::pair<std::string,ftxui::MenuOption>
as menu entry, and it's close to solution you provide in some case.
Another one is to modify MenuBase
class a little bit. First of all declare something like this:
using MenuOptions = std::vector<MenuOption>;
And then pass this instead of MenuOption
.
MenuBase(ConstStringListRef entries, int* selected, Ref<MenuOptions> options)
And edit Render
a little bit
Element Render() {
Elements elements;
bool is_menu_focused = Focused();
boxes_.resize(entries_.size());
for (size_t i = 0,j = 0; i < entries_.size(); ++i) {
bool is_focused = (focused_entry() == int(i)) && is_menu_focused;
bool is_selected = (*selected_ == int(i));
auto style = is_selected ? (is_focused ? options_[i]->style_selected_focused
: options_[i]->style_selected)
: (is_focused ? options_[i]->style_focused
: options_[i]->style_normal);
auto focus_management = !is_selected ? nothing
: is_menu_focused ? focus
: select;
auto icon = is_selected ? "> " : " ";
elements.push_back(text(icon + entries_[i]) | style | focus_management |
reflect(boxes_[i]));
if (j < options_.size()) j++;
}
return vbox(std::move(elements));
}
The advantage of this solution is that it provides flexible customization of each menu entry. As you can see, if you pass less options than entries, the remaining entries would "inherit" style of last option you give. So you can pass only one option and things will work in the old way ( some kind of 'backward compatibility" ).
@ArthurSonzogni, what is your thoughts about that ?
I think I would love something composable.
auto menu = Container::Vertical({
MenuEntry("text"),
MenuEntry("text", menu_entry_options_1),
MenuEntry("text", menu_entry_options_2),
MenuEntry("text", menu_entry_options_2),
MenuEntry("text", menu_entry_options_1),
}, &menu_entry_selected);
So adding the "MenuEntry" component that would behave similarly to what we see inside a menu.
I can also add the alias:
Component Menu(Components entries, int* selected_entry) {
return Container::Vertical(std::move(entries), selected_entry)
}
So that one could write:
auto menu = Menu({
MenuEntry("text"),
MenuEntry("text", menu_entry_options_1),
MenuEntry("text", menu_entry_options_2),
MenuEntry("text", menu_entry_options_2),
MenuEntry("text", menu_entry_options_1),
}, &menu_entry_selected);
Sorry, missclicked to close the issue.
I think I would love something composable.
auto menu = Container::Vertical({ MenuEntry("text"), MenuEntry("text", menu_entry_options_1), MenuEntry("text", menu_entry_options_2), MenuEntry("text", menu_entry_options_2), MenuEntry("text", menu_entry_options_1), }, &menu_entry_selected);
So adding the "MenuEntry" component that would behave similarly to what we see inside a menu.
I can also add the alias:
Component Menu(Components entries, int* selected_entry) { return Container::Vertical(std::move(entries), selected_entry) }
So that one could write:
auto menu = Menu({ MenuEntry("text"), MenuEntry("text", menu_entry_options_1), MenuEntry("text", menu_entry_options_2), MenuEntry("text", menu_entry_options_2), MenuEntry("text", menu_entry_options_1), }, &menu_entry_selected);
Well, that is even more intuitive solution, actually i like it so much. Thanks so much for replies ! Waiting for updates !
I am using the menu component to show lists of log messages. They're all dynamic and uses a FIFO based "entries" vector. Even though the component might not be designed for this use case, in general dynamic menus are very common in applications.
I believe that the solutions provided by @MattBystrin would work.
Maybe we need different paths or components since I like both suggestions but for dynamic content I cannot see how to make use of the one suggested by @ArthurSonzogni .
I am also not sure if all these simplified solutions will work in the long run, maybe a callback for rendering is needed to be able to compose a more dynamic view (like icons/animations etc).
@stefandxm , recently I made up some text non-selectable text scroller, based on Arthurs'. If you interested in, write me on email.
@MattBystrin iam interested in that for the details of the log item but for the log viewer itself i need something like the menu component since i use it to select logfile and log entry.
A video of the UI i made is available at https://www.youtube.com/watch?v=kieYzp5owds and the repo is at https://github.com/stefandxm/nglogger (the ngloggerui folder is the ui in the video). Please dont hang me for the UI code, I didnt have time to read up properly on the toolkit nor to write perfect code. But any pointers on how to use this library better is greatly appreciated.
Hey @MattBystrin and @stefandxm,
I added the MenuEntry component and improve support for scrolling using mouse wheel. Would you have any feedback?
Thank you @ArthurSonzogni ! Gonna test it on the weekend and give a feedback
@ArthurSonzogni sorry for not giving feedback for so long. Now I've just tested your example and view the code. I think it is quiet inconvenient to change the style dynamically, because I have to pass vectorMenu
interface - one vector with all MenuEntires
which we can pass by reference.
With FTXUI, you can pass almost everything by value or by pointer.
For instance:
{
MenuEntryOption style_1;
MenuEntryOption style_2;
int selected = 0;
auto menu = Container::Vertical(
{
MenuEntry(" 1. improve", &style_1),
MenuEntry(" 2. tolerant", &style_2),
MenuEntry(" 3. career", &style_1),
MenuEntry(" 4. cast", &style_2),
},
&selected);
// Side effect:
style_1.style_normal = Decorator(color(Color::Red));
}
Hey @MattBystrin and @stefandxm,
I added the MenuEntry component and improve support for scrolling using mouse wheel. Would you have any feedback?
I will definitely check it out but I am in a tight release right now so I will have to come back with feedback.
Hello, and thanks for the lib again) Is there any built-in way to customize (i.e. change color ) particular item in menu ?
First approach on my mind is to add
MenuOptions
for each entry, but it implies some changes inMenuBase
. If it is a necessary feature I can later send code for review, of course if it is not already implemented.Thanks!