#include "widgets.hpp" // import gucc #include "gucc/string_utils.hpp" // for make_multiline #include // for transform #include // for size_t #include // for back_insert_iterator #include // for shared_ptr, __shar... #include // for string, allocator #include // for move #include // for ftxui #include // for Renderer, Vertical #include // for ComponentBase, Com... #include // for ButtonOption, Inpu... #include // for ScreenInteractive #include // for operator|, Element #include // for Render #include // for Full, Screen #include // for Ref using namespace ftxui; namespace tui::detail { Element centered_widget(Component& container, const std::string_view& title, const Element& widget) noexcept { return vbox({ // -------- Title -------------- text(title.data()) | bold, filler(), // -------- Center Menu -------------- std::move(hbox({ filler(), border(std::move(vbox({ widget, separator(), container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25), }))), filler(), })) | center, filler(), }); } Element centered_widget_nocontrols(const std::string_view& title, const Element& widget) noexcept { return vbox({ // -------- Title -------------- text(title.data()) | bold, filler(), // -------- Center Menu -------------- std::move(hbox({ filler(), border(std::move(vbox({widget}))), filler(), })) | center, filler(), }); } Component controls_widget(const std::array&& titles, const std::array, 2>&& callbacks) noexcept { /* clang-format off */ auto button_ok = Button(titles[0].data(), callbacks[0], ButtonOption::WithoutBorder()); auto button_quit = Button(titles[1].data(), callbacks[1], ButtonOption::WithoutBorder()); /* clang-format on */ auto container = Container::Horizontal({ button_ok, Renderer([] { return filler() | size(WIDTH, GREATER_THAN, 3); }), button_quit, }); return container; } Element centered_interative_multi(const std::string_view& title, Component& widgets) noexcept { return vbox({ // -------- Title -------------- text(title.data()) | bold, filler(), // -------- Center Menu -------------- std::move(hbox({ filler(), border(std::move(vbox({ widgets->Render(), }))), filler(), })) | center, filler(), }); } Element multiline_text(std::vector&& lines) noexcept { Elements multiline; std::transform(std::make_move_iterator(lines.begin()), std::make_move_iterator(lines.end()), std::back_inserter(multiline), [=](auto&& line) -> Element { return text(std::forward(line)); }); return std::move(vbox(std::move(multiline))) | frame; } Components from_vector_checklist(const std::vector& opts, bool* const opts_state) noexcept { Components components; for (size_t i = 0; i < opts.size(); ++i) { auto&& component = Checkbox(&opts[i], &opts_state[i]); components.emplace_back(std::move(component)); } return components; } std::string from_checklist_string(const std::vector& opts, const bool* const opts_state) noexcept { std::string res{}; for (size_t i = 0; i < opts.size(); ++i) { if (opts_state[i]) { res += opts[i] + " "; } } /* clang-format off */ if (res.ends_with(" ")) { res.pop_back(); } /* clang-format on */ return res; } std::vector from_checklist_vector(const std::vector& opts, const bool* const opts_state) noexcept { std::vector res{}; for (size_t i = 0; i < opts.size(); ++i) { if (opts_state[i]) { res.push_back(opts[i]); } } return res; } void msgbox_widget(const std::string_view& content, Decorator boxsize) noexcept { auto screen = ScreenInteractive::Fullscreen(); /* clang-format off */ auto button_back = Button("OK", screen.ExitLoopClosure(), ButtonOption::WithoutBorder()); auto container = Container::Horizontal({button_back}); auto renderer = Renderer(container, [&] { return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(gucc::utils::make_multiline(content)) | boxsize); }); /* clang-format on */ screen.Loop(renderer); } bool inputbox_widget(std::string& value, const std::string_view& content, Decorator boxsize, bool password) noexcept { auto screen = ScreenInteractive::Fullscreen(); bool success{}; auto ok_callback = [&] { success = true; screen.ExitLoopClosure()(); }; const InputOption input_option{.on_enter = ok_callback, .password = password}; auto input_value = Input(&value, "", input_option); auto content_container = Renderer([&] { return multiline_text(gucc::utils::make_multiline(content)) | hcenter | boxsize; }); auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}); auto controls = Renderer(controls_container, [&] { return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); }); auto global = Container::Vertical({ content_container, Renderer([] { return separator(); }), input_value, Renderer([] { return separator(); }), controls, }); auto renderer = Renderer(global, [&] { return detail::centered_interative_multi("New CLI Installer", global); }); screen.Loop(renderer); return success; } void infobox_widget(const std::string_view& content, Decorator boxsize) noexcept { auto screen = Screen::Create( Dimension::Full(), // Width Dimension::Full() // Height ); auto element = detail::centered_widget_nocontrols("New CLI Installer", detail::multiline_text(gucc::utils::make_multiline(content)) | vcenter | boxsize); Render(screen, element); screen.Print(); } bool yesno_widget(const std::string_view& content, Decorator boxsize) noexcept { auto screen = ScreenInteractive::Fullscreen(); bool success{}; auto ok_callback = [&] { success = true; screen.ExitLoopClosure()(); }; auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}); auto controls = Renderer(controls_container, [&] { return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); }); auto container = Container::Horizontal({ controls, }); auto renderer = Renderer(container, [&] { return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(gucc::utils::make_multiline(content)) | hcenter | boxsize); }); screen.Loop(renderer); return success; } bool yesno_widget(ftxui::Component& container, Decorator boxsize) noexcept { auto screen = ScreenInteractive::Fullscreen(); auto content = Renderer(container, [&] { return container->Render() | hcenter | boxsize; }); bool success{}; auto ok_callback = [&] { success = true; screen.ExitLoopClosure()(); }; auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}); auto controls = Renderer(controls_container, [&] { return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); }); auto global = Container::Vertical({ content, Renderer([] { return separator(); }), controls, }); auto renderer = Renderer(global, [&] { return detail::centered_interative_multi("New CLI Installer", global); }); screen.Loop(renderer); return success; } void menu_widget(const std::vector& entries, const std::function&& ok_callback, std::int32_t* selected, ScreenInteractive* screen, const std::string_view& text, const WidgetBoxSize widget_sizes) noexcept { MenuOption menu_option{.on_enter = ok_callback}; auto menu = Menu(&entries, selected, &menu_option); auto content = Renderer(menu, [&] { return menu->Render() | center | widget_sizes.content_size; }); auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen->ExitLoopClosure()}); auto controls = Renderer(controls_container, [&] { return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); }); Components children{}; if (!text.empty()) { children = { Renderer([&] { return detail::multiline_text(gucc::utils::make_multiline(text)) | widget_sizes.text_size; }), Renderer([] { return separator(); }), content, Renderer([] { return separator(); }), controls}; } else { children = { content, Renderer([] { return separator(); }), controls}; } auto global{Container::Vertical(children)}; auto renderer = Renderer(global, [&] { return detail::centered_interative_multi("New CLI Installer", global); }); screen->Loop(renderer); } void radiolist_widget(const std::vector& entries, const std::function&& ok_callback, std::int32_t* selected, ScreenInteractive* screen, const WidgetBoxRes& widget_res, const WidgetBoxSize widget_sizes) noexcept { auto radiolist = Container::Vertical({ Radiobox(&entries, selected), }); auto content = Renderer(radiolist, [&] { return radiolist->Render() | center | widget_sizes.content_size; }); auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen->ExitLoopClosure()}); auto controls = Renderer(controls_container, [&] { return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); }); Components children{}; if (!widget_res.text.empty()) { children = { Renderer([&] { return detail::multiline_text(gucc::utils::make_multiline(widget_res.text)) | widget_sizes.text_size; }), Renderer([] { return separator(); }), content, Renderer([] { return separator(); }), controls}; } else { children = { content, Renderer([] { return separator(); }), controls}; } auto global{Container::Vertical(children)}; auto renderer = Renderer(global, [&] { return detail::centered_interative_multi(widget_res.title, global); }); screen->Loop(renderer); } void checklist_widget(const std::vector& opts, const std::function&& ok_callback, bool* opts_state, ScreenInteractive* screen, const std::string_view& text, const std::string_view& title, const WidgetBoxSize widget_sizes) noexcept { auto checklist{Container::Vertical(detail::from_vector_checklist(opts, opts_state))}; auto content = Renderer(checklist, [&] { return checklist->Render() | center | widget_sizes.content_size; }); auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen->ExitLoopClosure()}); auto controls = Renderer(controls_container, [&] { return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); }); Components children{}; if (!text.empty()) { children = { Renderer([&] { return std::move(detail::multiline_text(gucc::utils::make_multiline(text))) | widget_sizes.text_size; }), Renderer([] { return separator(); }), content, Renderer([] { return separator(); }), controls}; } else { children = { content, Renderer([] { return separator(); }), controls}; } auto global{Container::Vertical(children)}; auto renderer = Renderer(global, [&] { return detail::centered_interative_multi(title, global); }); screen->Loop(renderer); } } // namespace tui::detail