diff --git a/examples/component/CMakeLists.txt b/examples/component/CMakeLists.txt index 0ef9a82..c30dd6d 100644 --- a/examples/component/CMakeLists.txt +++ b/examples/component/CMakeLists.txt @@ -11,6 +11,7 @@ example(input) example(menu) example(menu2) example(menu_multiple) +example(menu_entries) example(menu_style) example(modal_dialog) example(print_key_press) diff --git a/examples/component/menu_entries.cpp b/examples/component/menu_entries.cpp new file mode 100644 index 0000000..b24173d --- /dev/null +++ b/examples/component/menu_entries.cpp @@ -0,0 +1,90 @@ +#include // for function +#include // for basic_ostream::operator<<, operator<<, endl, basic_ostream, basic_ostream<>::__ostream_type, cout, ostream +#include // for string, basic_string, allocator +#include // for vector + +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for Menu +#include "ftxui/component/component_options.hpp" // for MenuOption +#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive +using namespace ftxui; + +// Define a special style for some menu entry. +MenuEntryOption Colored(ftxui::Color c) { + MenuEntryOption special_style; + special_style.style_normal = Decorator(color(c)); + special_style.style_focused = Decorator(color(c)) | inverted; + special_style.style_selected = Decorator(color(c)) | bold; + special_style.style_selected_focused = Decorator(color(c)) | inverted | bold; + return special_style; +} + +int main(int argc, const char* argv[]) { + auto screen = ScreenInteractive::TerminalOutput(); + + //Black = 0, + //Red = 1, + //Green = 2, + //Yellow = 3, + //Blue = 4, + //Magenta = 5, + //Cyan = 6, + //GrayLight = 7, + //GrayDark = 8, + //RedLight = 9, + //GreenLight = 10, + //YellowLight = 11, + //BlueLight = 12, + //MagentaLight = 13, + //CyanLight = 14, + //White = 15, + + int selected = 0; + auto menu = Container::Vertical( + { + MenuEntry(" 1. improve"), + MenuEntry(" 2. tolerant"), + MenuEntry(" 3. career"), + MenuEntry(" 4. cast"), + MenuEntry(" 5. question"), + + Renderer([] { return separator(); }), + + MenuEntry(" 6. rear", Colored(Color::Red)), + MenuEntry(" 7. drown", Colored(Color::Yellow)), + MenuEntry(" 8. nail", Colored(Color::Green)), + MenuEntry(" 9. quit", Colored(Color::Cyan)), + MenuEntry("10. decorative", Colored(Color::Blue)), + + Renderer([] { return separator(); }), + + MenuEntry("11. costume"), + MenuEntry("12. pick"), + MenuEntry("13. oral"), + MenuEntry("14. minister"), + MenuEntry("15. football"), + MenuEntry("16. welcome"), + MenuEntry("17. copper"), + MenuEntry("18. inhabitant"), + MenuEntry("19. fortune"), + }, + &selected); + + // Display together the menu with a border + auto renderer = Renderer(menu, [&] { + return vbox({ + hbox(text("selected = "), text(std::to_string(selected))), + separator(), + menu->Render() | frame | size(HEIGHT, LESS_THAN, 10), + }) | + border; + }); + + screen.Loop(renderer); + + std::cout << "Selected element = " << selected << std::endl; +} + +// Copyright 2020 Arthur Sonzogni. All rights reserved. +// Use of this source code is governed by the MIT license that can be found in +// the LICENSE file. diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index beab06f..c2e6036 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -37,6 +37,7 @@ Component Input(StringRef content, Component Menu(ConstStringListRef entries, int* selected_, Ref = {}); +Component MenuEntry(ConstStringRef label, Ref = {}); Component Radiobox(ConstStringListRef entries, int* selected_, Ref option = {}); diff --git a/include/ftxui/component/component_options.hpp b/include/ftxui/component/component_options.hpp index a56a3f4..dfcda02 100644 --- a/include/ftxui/component/component_options.hpp +++ b/include/ftxui/component/component_options.hpp @@ -23,6 +23,16 @@ struct MenuOption { Ref focused_entry = 0; }; +/// @brief Option for the MenuEntry component. +/// @ingroup component +struct MenuEntryOption { + Decorator style_normal = nothing; ///< style. + Decorator style_focused = inverted; ///< Style when focused. + Decorator style_selected = bold; ///< Style when selected. + Decorator style_selected_focused = + Decorator(inverted) | bold; ///< Style when selected and focused. +}; + /// @brief Option for the Button component. /// @ingroup component struct ButtonOption { diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 8694aa0..7d5c728 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -149,6 +149,51 @@ Component Menu(ConstStringListRef entries, return Make(entries, selected, std::move(option)); } +Component MenuEntry(ConstStringRef label, Ref option) { + class Impl : public ComponentBase { + public: + Impl(ConstStringRef label, Ref option) + : label_(std::move(label)), option_(std::move(option)) {} + + private: + Element Render() override { + bool focused = Focused(); + auto style = + hovered_ ? (focused ? option_->style_selected_focused + : option_->style_selected) + : (focused ? option_->style_focused : option_->style_normal); + auto focus_management = focused ? select : nothing; + auto label = focused ? "> " + (*label_) // + : " " + (*label_); + return text(label) | style | focus_management | reflect(box_); + } + bool Focusable() const override { return true; } + bool OnEvent(Event event) override { + if (!event.is_mouse()) + return false; + + hovered_ = box_.Contain(event.mouse().x, event.mouse().y); + + if (!hovered_) + return false; + + if (event.mouse().button == Mouse::Left && + event.mouse().motion == Mouse::Released) { + TakeFocus(); + return true; + } + + return false; + } + ConstStringRef label_; + Ref option_; + Box box_; + bool hovered_ = false; + }; + + return Make(std::move(label), std::move(option)); +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved.