New-Cli-Installer/src/widgets.cpp

370 lines
13 KiB
C++
Raw Normal View History

#include "widgets.hpp"
2021-12-27 02:42:19 +08:00
#include "utils.hpp" // for make_multiline
2021-12-27 02:42:19 +08:00
#include <algorithm> // for transform
#include <cstddef> // for size_t
#include <iterator> // for back_insert_iterator
#include <memory> // for shared_ptr, __shar...
#include <string> // for string, allocator
#include <utility> // for move
#include <ftxui/component/captured_mouse.hpp> // for ftxui
#include <ftxui/component/component.hpp> // for Renderer, Vertical
#include <ftxui/component/component_base.hpp> // for ComponentBase, Com...
#include <ftxui/component/component_options.hpp> // for ButtonOption, Inpu...
#include <ftxui/component/screen_interactive.hpp> // for ScreenInteractive
#include <ftxui/dom/elements.hpp> // for operator|, Element
#include <ftxui/dom/node.hpp> // for Render
#include <ftxui/screen/screen.hpp> // for Full, Screen
#include <ftxui/util/ref.hpp> // 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 --------------
hbox({
filler(),
border(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 --------------
hbox({
filler(),
border(vbox({widget})),
filler(),
}) | center,
filler(),
});
}
Component controls_widget(const std::array<std::string_view, 2>&& titles, const std::array<std::function<void()>, 2>&& callbacks, ButtonOption* button_option) noexcept {
/* clang-format off */
auto button_ok = Button(titles[0].data(), callbacks[0], button_option);
auto button_quit = Button(titles[1].data(), callbacks[1], button_option);
/* 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 --------------
hbox({
filler(),
border(vbox({
widgets->Render(),
})),
filler(),
}) | center,
filler(),
});
}
Element multiline_text(const std::vector<std::string>& lines) noexcept {
Elements multiline;
std::transform(lines.cbegin(), lines.cend(), std::back_inserter(multiline),
[=](const std::string& line) -> Element { return text(line); });
return vbox(std::move(multiline)) | frame;
}
Components from_vector_checklist(const std::vector<std::string>& opts, bool* 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(component);
}
return components;
}
std::string from_checklist_string(const std::vector<std::string>& opts, bool* 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<std::string> from_checklist_vector(const std::vector<std::string>& opts, bool* opts_state) noexcept {
std::vector<std::string> 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_option = ButtonOption();
button_option.border = false;
auto button_back = Button("OK", screen.ExitLoopClosure(), &button_option);
2022-01-07 03:23:36 +08:00
auto container = Container::Horizontal({button_back});
auto renderer = Renderer(container, [&] {
2022-01-07 03:23:36 +08:00
return centered_widget(container, "New CLI Installer", multiline_text(utils::make_multiline(content)) | boxsize);
});
2022-01-07 03:23:36 +08:00
/* clang-format on */
screen.Loop(renderer);
}
2021-12-23 05:41:44 +08:00
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()();
};
2021-12-23 05:41:44 +08:00
InputOption input_option{.on_enter = ok_callback, .password = password};
auto input_value = Input(&value, "", input_option);
auto content_container = Renderer([&] {
return multiline_text(utils::make_multiline(content)) | hcenter | boxsize;
});
ButtonOption button_option{.border = false};
auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}, &button_option);
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 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
);
2022-01-09 08:41:43 +08:00
auto element = centered_widget_nocontrols("New CLI Installer", multiline_text(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()();
};
ButtonOption button_option{.border = false};
auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}, &button_option);
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, [&] {
2022-01-09 08:41:43 +08:00
return centered_widget(container, "New CLI Installer", multiline_text(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()();
};
ButtonOption button_option{.border = false};
auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}, &button_option);
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 centered_interative_multi("New CLI Installer", global);
});
screen.Loop(renderer);
return success;
}
2021-12-27 03:21:33 +08:00
void menu_widget(const std::vector<std::string>& entries, const std::function<void()>&& ok_callback, std::int32_t* selected, ScreenInteractive* screen, const std::string_view& text, const WidgetBoxSize widget_sizes) noexcept {
2021-12-19 06:40:37 +08:00
MenuOption menu_option{.on_enter = ok_callback};
auto menu = Menu(&entries, selected, &menu_option);
auto content = Renderer(menu, [&] {
2021-12-27 03:21:33 +08:00
return menu->Render() | center | widget_sizes.content_size;
});
ButtonOption button_option{.border = false};
2022-01-06 18:20:56 +08:00
auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen->ExitLoopClosure()}, &button_option);
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(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 centered_interative_multi("New CLI Installer", global);
});
screen->Loop(renderer);
}
2022-03-01 06:43:41 +08:00
void radiolist_widget(const std::vector<std::string>& entries, const std::function<void()>&& ok_callback, std::int32_t* selected, ScreenInteractive* screen, const WidgetBoxRes widget_res, const WidgetBoxSize widget_sizes) noexcept {
2022-01-06 18:20:56 +08:00
auto radiolist = Container::Vertical({
Radiobox(&entries, selected),
});
2022-01-07 03:23:36 +08:00
auto content = Renderer(radiolist, [&] {
2022-01-06 18:20:56 +08:00
return radiolist->Render() | center | widget_sizes.content_size;
2022-01-07 03:23:36 +08:00
});
2022-01-06 18:20:56 +08:00
ButtonOption button_option{.border = false};
auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen->ExitLoopClosure()}, &button_option);
auto controls = Renderer(controls_container, [&] {
return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25);
});
2021-12-23 05:41:44 +08:00
Components children{};
2022-03-01 06:43:41 +08:00
if (!widget_res.text.empty()) {
2021-12-23 05:41:44 +08:00
children = {
2022-03-01 06:43:41 +08:00
Renderer([&] { return detail::multiline_text(utils::make_multiline(widget_res.text)) | widget_sizes.text_size; }),
2021-12-23 05:41:44 +08:00
Renderer([] { return separator(); }),
content,
Renderer([] { return separator(); }),
controls};
} else {
children = {
content,
Renderer([] { return separator(); }),
controls};
}
auto global{Container::Vertical(children)};
auto renderer = Renderer(global, [&] {
2022-03-01 06:43:41 +08:00
return centered_interative_multi(widget_res.title, global);
});
screen->Loop(renderer);
}
2022-01-07 03:23:36 +08:00
void checklist_widget(const std::vector<std::string>& opts, const std::function<void()>&& 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;
});
ButtonOption button_option{.border = false};
auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen->ExitLoopClosure()}, &button_option);
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(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 centered_interative_multi(title, global);
});
screen->Loop(renderer);
}
} // namespace tui::detail