From a63d00057c66dedfdbd853bcf95e4be7acc0cd88 Mon Sep 17 00:00:00 2001 From: Vladislav Nepogodin Date: Thu, 6 Jan 2022 23:23:36 +0400 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=20=20cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tui.cpp | 134 +++++++----------------------------------------- src/utils.cpp | 124 +++++++++++++++++++++++++++++--------------- src/utils.hpp | 2 +- src/widgets.cpp | 50 +++++++++++++++--- src/widgets.hpp | 3 +- 5 files changed, 145 insertions(+), 168 deletions(-) diff --git a/src/tui.cpp b/src/tui.cpp index b04896e..458c1b8 100644 --- a/src/tui.cpp +++ b/src/tui.cpp @@ -24,6 +24,7 @@ namespace fs = std::filesystem; #pragma clang diagnostic ignored "-Wold-style-cast" #include +#include #pragma clang diagnostic pop #else @@ -687,16 +688,9 @@ void install_base() noexcept { // Create the base list of packages std::vector install_packages{}; - std::unique_ptr kernels_state{new bool[available_kernels.size()]{false}}; - auto kernels{Container::Vertical(detail::from_vector_checklist(available_kernels, kernels_state.get()))}; - - auto screen = ScreenInteractive::Fullscreen(); - auto content = Renderer(kernels, [&] { - return kernels->Render() | center | size(HEIGHT, GREATER_THAN, 10) | size(WIDTH, GREATER_THAN, 40) | vscroll_indicator | yframe | flex; - }); - + auto screen = ScreenInteractive::Fullscreen(); std::string packages{}; auto ok_callback = [&] { packages = detail::from_checklist_string(available_kernels, kernels_state.get()); @@ -717,30 +711,12 @@ void install_base() noexcept { screen.ExitLoopClosure()(); }; - ButtonOption button_option{.border = false}; - auto controls_container = detail::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); - }); - static constexpr auto InstStandBseBody = "\nThe base package group will be installed automatically.\nThe base-devel package group is required to use the Arch User Repository (AUR).\n"; static constexpr auto UseSpaceBar = "Use [Spacebar] to de/select options listed."; const auto& kernels_options_body = fmt::format("\n{}{}\n", InstStandBseBody, UseSpaceBar); - auto global = Container::Vertical({ - Renderer([&] { return detail::multiline_text(utils::make_multiline(kernels_options_body)); }), - Renderer([] { return separator(); }), - content, - Renderer([] { return separator(); }), - controls, - }); - auto renderer = Renderer(global, [&] { - constexpr auto title = "New CLI Installer | Install Base"; - return detail::centered_interative_multi(title, global); - }); - - screen.Loop(renderer); + constexpr auto base_title = "New CLI Installer | Install Base"; + detail::checklist_widget(available_kernels, ok_callback, kernels_state.get(), &screen, kernels_options_body, base_title, {.text_size = nothing}); /* clang-format off */ if (packages.empty()) { return; } @@ -788,16 +764,9 @@ void install_desktop() noexcept { // Create the base list of packages std::vector install_packages{}; - std::unique_ptr des_state{new bool[available_des.size()]{false}}; - auto kernels{Container::Vertical(detail::from_vector_checklist(available_des, des_state.get()))}; - - auto screen = ScreenInteractive::Fullscreen(); - auto content = Renderer(kernels, [&] { - return kernels->Render() | center | size(HEIGHT, GREATER_THAN, 10) | size(WIDTH, GREATER_THAN, 40) | vscroll_indicator | yframe | flex; - }); - + auto screen = ScreenInteractive::Fullscreen(); std::string desktop_env{}; auto ok_callback = [&] { desktop_env = detail::from_checklist_string(available_des, des_state.get()); @@ -805,30 +774,12 @@ void install_desktop() noexcept { screen.ExitLoopClosure()(); }; - ButtonOption button_option{.border = false}; - auto controls_container = detail::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); - }); - static constexpr auto InstManDEBody = "\nPlease choose a desktop environment.\n"; static constexpr auto UseSpaceBar = "Use [Spacebar] to de/select options listed."; - const auto& kernels_options_body = fmt::format("\n{}{}\n", InstManDEBody, UseSpaceBar); - auto global = Container::Vertical({ - Renderer([&] { return detail::multiline_text(utils::make_multiline(kernels_options_body)); }), - Renderer([] { return separator(); }), - content, - Renderer([] { return separator(); }), - controls, - }); + const auto& des_options_body = fmt::format("\n{}{}\n", InstManDEBody, UseSpaceBar); - auto renderer = Renderer(global, [&] { - constexpr auto title = "New CLI Installer | Install Desktop"; - return detail::centered_interative_multi(title, global); - }); - - screen.Loop(renderer); + constexpr auto desktop_title = "New CLI Installer | Install Desktop"; + detail::checklist_widget(available_des, ok_callback, des_state.get(), &screen, des_options_body, desktop_title, {.text_size = nothing}); /* clang-format off */ if (desktop_env.empty()) { return; } @@ -1122,39 +1073,13 @@ void auto_partition() noexcept { // Show created partitions const auto& disk_list = utils::exec(fmt::format("lsblk {} -o NAME,TYPE,FSTYPE,SIZE", device_info)); - - auto screen = ScreenInteractive::Fullscreen(); - /* clang-format off */ - auto button_option = ButtonOption(); - button_option.border = false; - auto button_back = Button("Back", screen.ExitLoopClosure(), &button_option); - - auto container = Container::Horizontal({button_back}); - auto renderer = Renderer(container, [&] { - return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(utils::make_multiline(disk_list)) | size(HEIGHT, GREATER_THAN, 5)); - }); - /* clang-format on */ - - screen.Loop(renderer); + detail::msgbox_widget(disk_list, size(HEIGHT, GREATER_THAN, 5)); } // Simple code to show devices / partitions. void show_devices() noexcept { - auto screen = ScreenInteractive::Fullscreen(); const auto& lsblk = utils::exec("lsblk -o NAME,MODEL,TYPE,FSTYPE,SIZE,MOUNTPOINT | grep \"disk\\|part\\|lvm\\|crypt\\|NAME\\|MODEL\\|TYPE\\|FSTYPE\\|SIZE\\|MOUNTPOINT\""); - - /* clang-format off */ - auto button_option = ButtonOption(); - button_option.border = false; - auto button_back = Button("Back", screen.ExitLoopClosure(), &button_option); - - auto container = Container::Horizontal({button_back}); - auto renderer = Renderer(container, [&] { - return detail::centered_widget(container, "New CLI Installer", detail::multiline_text(utils::make_multiline(lsblk)) | size(HEIGHT, GREATER_THAN, 5)); - }); - /* clang-format on */ - - screen.Loop(renderer); + detail::msgbox_widget(lsblk, size(HEIGHT, GREATER_THAN, 5)); } // This function does not assume that the formatted device is the Root installation device as @@ -1305,42 +1230,19 @@ void mount_opts() noexcept { /* clang-format on */ } - auto flags = Container::Vertical(detail::from_vector_checklist(fs_opts, fs_opts_state.get())); - - auto screen = ScreenInteractive::Fullscreen(); - auto content = Renderer(flags, [&] { - return flags->Render() | center | size(HEIGHT, GREATER_THAN, 10) | size(WIDTH, GREATER_THAN, 40) | vscroll_indicator | yframe | flex; - }); - + auto screen = ScreenInteractive::Fullscreen(); auto& mount_opts_info = std::get(config_data["MOUNT_OPTS"]); auto ok_callback = [&] { mount_opts_info = detail::from_checklist_string(fs_opts, fs_opts_state.get()); screen.ExitLoopClosure()(); }; - ButtonOption button_option{.border = false}; - auto controls_container = detail::controls_widget({"OK", "Cancel"}, {ok_callback, screen.ExitLoopClosure()}, &button_option); + const auto& file_sys_formatted = utils::exec(fmt::format("echo {} | sed \"s/.*\\.//g;s/-.*//g\"", file_sys)); + const auto& fs_title = fmt::format("New CLI Installer | {}", file_sys_formatted); + const auto& content_size = size(HEIGHT, GREATER_THAN, 10) | size(WIDTH, GREATER_THAN, 40) | vscroll_indicator | yframe | flex; - auto controls = Renderer(controls_container, [&] { - return controls_container->Render() | hcenter | size(HEIGHT, LESS_THAN, 3) | size(WIDTH, GREATER_THAN, 25); - }); - - std::string mount_options_body = "\nUse [Space] to de/select the desired mount\noptions and review carefully. Please do not\nselect multiple versions of the same option.\n"; - auto global = Container::Vertical({ - Renderer([&] { return detail::multiline_text(utils::make_multiline(mount_options_body)); }), - Renderer([] { return separator(); }), - content, - Renderer([] { return separator(); }), - controls, - }); - - auto renderer = Renderer(global, [&] { - const auto& file_sys_formatted = utils::exec(fmt::format("echo {} | sed \"s/.*\\.//g;s/-.*//g\"", file_sys)); - const auto& title = fmt::format("New CLI Installer | {}", file_sys_formatted); - return detail::centered_interative_multi(title, global); - }); - - screen.Loop(renderer); + static constexpr auto mount_options_body = "\nUse [Space] to de/select the desired mount\noptions and review carefully. Please do not\nselect multiple versions of the same option.\n"; + detail::checklist_widget(fs_opts, ok_callback, fs_opts_state.get(), &screen, mount_options_body, fs_title, {content_size, nothing}); // Now clean up the file mount_opts_info = utils::exec(fmt::format("echo \"{}\" | sed \'s/ /,/g\'", mount_opts_info)); @@ -1651,7 +1553,7 @@ void make_esp() noexcept { answer = radiobox_list[static_cast(selected)]; screen.ExitLoopClosure()(); }; - detail::radiolist_widget(radiobox_list, ok_callback, &selected, &screen, MntUefiMessage, detail::WidgetBoxSize{.text_size = nothing}); + detail::radiolist_widget(radiobox_list, ok_callback, &selected, &screen, MntUefiMessage, {.text_size = nothing}); } /* clang-format off */ @@ -1824,7 +1726,7 @@ void mount_partitions() noexcept { if (partition == "Done") { make_esp(); utils::get_cryptroot(); - // get_cryptboot(); + utils::get_cryptboot(); return; } config_data["MOUNT"] = ""; diff --git a/src/utils.cpp b/src/utils.cpp index babec60..d1d7205 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -71,7 +70,6 @@ namespace ranges = std::ranges; namespace fs = std::filesystem; namespace utils { -static constexpr std::int32_t CONNECTION_TIMEOUT = 15; bool is_connected() noexcept { #ifdef NDEVENV @@ -383,60 +381,101 @@ void get_cryptroot() noexcept { auto& config_data = config_instance->data(); // Identify if /mnt or partition is type "crypt" (LUKS on LVM, or LUKS alone) - if ((utils::exec("lsblk | sed -r 's/^[^[:alnum:]]+//' | awk '/\\/mnt$/ {print $6}' | grep -q crypt", true) == "0") - || (utils::exec("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt$/,/part/p\" | awk '{print $6}' | grep -q crypt", true) == "0")) { - config_data["LUKS"] = 1; - auto& luks_name = std::get(config_data["LUKS_ROOT_NAME"]); - const auto& luks_dev = std::get(config_data["LUKS_DEV"]); - luks_name = utils::exec("mount | awk '/\\/mnt / {print $1}' | sed s~/dev/mapper/~~g | sed s~/dev/~~g"); - // Get the name of the Luks device - if (utils::exec("lsblk -i | grep -q -e \"crypt /mnt\"", true) != "0") { - // Mountpoint is not directly on LUKS device, so we need to get the crypt device above the mountpoint - luks_name = utils::exec("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt$/,/crypt/p\" | awk '/crypt/ {print $1}'"); - } + if ((utils::exec("lsblk | sed -r 's/^[^[:alnum:]]+//' | awk '/\\/mnt$/ {print $6}' | grep -q crypt", true) != "0") + || (utils::exec("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt$/,/part/p\" | awk '{print $6}' | grep -q crypt", true) != "0")) { + return; + } - const auto& check_cryptparts = [&](const auto cryptparts, auto functor) { - for (const auto& cryptpart : cryptparts) { - if (!utils::exec(fmt::format("lsblk -lno NAME {} | grep \"{}\"", cryptpart, luks_name)).empty()) { - functor(cryptpart); - return true; - } + config_data["LUKS"] = 1; + auto& luks_name = std::get(config_data["LUKS_ROOT_NAME"]); + luks_name = utils::exec("mount | awk '/\\/mnt / {print $1}' | sed s~/dev/mapper/~~g | sed s~/dev/~~g"); + // Get the name of the Luks device + if (utils::exec("lsblk -i | grep -q -e \"crypt /mnt\"", true) != "0") { + // Mountpoint is not directly on LUKS device, so we need to get the crypt device above the mountpoint + luks_name = utils::exec("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt$/,/crypt/p\" | awk '/crypt/ {print $1}'"); + } + + const auto& check_cryptparts = [&luks_name](const auto& cryptparts, auto functor) { + for (const auto& cryptpart : cryptparts) { + if (!utils::exec(fmt::format("lsblk -lno NAME {} | grep \"{}\"", cryptpart, luks_name)).empty()) { + functor(cryptpart); } - return false; - }; + } + }; - // Check if LUKS on LVM (parent = lvm /dev/mapper/...) - auto cryptparts = utils::make_multiline(utils::exec("lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep \"lvm\" | grep \"/mnt$\" | grep -i \"crypto_luks\" | uniq | awk '{print \"/dev/mapper/\"$1}'")); - auto check_functor = [&](const auto cryptpart) { + // Check if LUKS on LVM (parent = lvm /dev/mapper/...) + auto temp_out = utils::exec("lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep \"lvm\" | grep \"/mnt$\" | grep -i \"crypto_luks\" | uniq | awk '{print \"/dev/mapper/\"$1}'"); + if (!temp_out.empty()) { + const auto& cryptparts = utils::make_multiline(temp_out); + const auto& check_functor = [&](const auto cryptpart) { config_data["LUKS_DEV"] = fmt::format("cryptdevice={}:{}", cryptpart, luks_name); config_data["LVM"] = 1; }; - if (check_cryptparts(cryptparts, check_functor)) { - return; - } + check_cryptparts(cryptparts, check_functor); + return; + } - // Check if LVM on LUKS - cryptparts = utils::make_multiline(utils::exec("lsblk -lno NAME,FSTYPE,TYPE | grep \" crypt$\" | grep -i \"LVM2_member\" | uniq | awk '{print \"/dev/mapper/\"$1}'")); - const auto& check_lvm_luks_dev = [&]([[maybe_unused]] const auto cryptpart) { + // Check if LVM on LUKS + temp_out = utils::exec("lsblk -lno NAME,FSTYPE,TYPE | grep \" crypt$\" | grep -i \"LVM2_member\" | uniq | awk '{print \"/dev/mapper/\"$1}'"); + if (!temp_out.empty()) { + const auto& cryptparts = utils::make_multiline(temp_out); + const auto& check_functor = [&]([[maybe_unused]] const auto cryptpart) { auto& luks_uuid = std::get(config_data["LUKS_UUID"]); luks_uuid = utils::exec("lsblk -ino NAME,FSTYPE,TYPE,MOUNTPOINT,UUID | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt /,/part/p\" | awk '/crypto_LUKS/ {print $4}'"); config_data["LUKS_DEV"] = fmt::format("cryptdevice=UUID={}:{}", luks_uuid, luks_name); config_data["LVM"] = 1; }; - if (check_cryptparts(cryptparts, check_lvm_luks_dev)) { - return; - } + check_cryptparts(cryptparts, check_functor); + return; + } - // Check if LUKS alone (parent = part /dev/...) - cryptparts = utils::make_multiline(utils::exec("lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep \"/mnt$\" | grep \"part\" | grep -i \"crypto_luks\" | uniq | awk '{print \"/dev/\"$1}'")); - const auto& check_func_dev = [&](const auto cryptpart) { + // Check if LUKS alone (parent = part /dev/...) + temp_out = utils::exec("lsblk -lno NAME,FSTYPE,TYPE,MOUNTPOINT | grep \"/mnt$\" | grep \"part\" | grep -i \"crypto_luks\" | uniq | awk '{print \"/dev/\"$1}'"); + if (!temp_out.empty()) { + const auto& cryptparts = utils::make_multiline(temp_out); + const auto& check_functor = [&](const auto cryptpart) { auto& luks_uuid = std::get(config_data["LUKS_UUID"]); luks_uuid = utils::exec(fmt::format("lsblk -lno UUID,TYPE,FSTYPE {} | grep \"part\" | grep -i \"crypto_luks\" | {}", cryptpart, "awk '{print $1}'")); config_data["LUKS_DEV"] = fmt::format("cryptdevice=UUID={}:{}", luks_uuid, luks_name); }; - if (check_cryptparts(cryptparts, check_func_dev)) { - return; - } + check_cryptparts(cryptparts, check_functor); + return; + } +} + +void get_cryptboot() noexcept { + auto* config_instance = Config::instance(); + auto& config_data = config_instance->data(); + + // If /boot is encrypted + if ((utils::exec("lsblk | sed -r 's/^[^[:alnum:]]+//' | awk '/\\/mnt\\/boot$/ {print $6}' | grep -q crypt", true) != "0") + || (utils::exec("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt\\/boot$/,/part/p\" | awk '{print $6}' | grep -q crypt", true) != "0")) { + return; + } + config_data["LUKS"] = 1; + + // Mountpoint is directly on the LUKS device, so LUKS deivece is the same as root name + std::string boot_name{utils::exec("mount | awk '/\\/mnt\\/boot / {print $1}' | sed s~/dev/mapper/~~g | sed s~/dev/~~g")}; + // Get UUID of the encrypted /boot + std::string boot_uuid{utils::exec("lsblk -lno UUID,MOUNTPOINT | awk '/\\mnt\\/boot$/ {print $1}'")}; + + // Get the name of the Luks device + if (utils::exec("lsblk -i | grep -q -e \"crypt /mnt\"", true) != "0") { + // Mountpoint is not directly on LUKS device, so we need to get the crypt device above the mountpoint + boot_name = utils::exec("lsblk -i | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt\\/boot$/,/crypt/p\" | awk '/crypt/ {print $1}'"); + boot_uuid = utils::exec("lsblk -ino NAME,FSTYPE,TYPE,MOUNTPOINT,UUID | tac | sed -r 's/^[^[:alnum:]]+//' | sed -n -e \"/\\/mnt\\/boot /,/part/p\" | awk '/crypto_LUKS/ {print $4}'"); + } + + // Check if LVM on LUKS + if (utils::exec("lsblk -lno TYPE,MOUNTPOINT | grep \"/mnt/boot$\" | grep -q lvm", true) == "0") { + config_data["LVM"] = 1; + } + + // Add cryptdevice to LUKS_DEV, if not already present (if on same LVM on LUKS as /) + auto& luks_dev = std::get(config_data["LUKS_DEV"]); + const auto& found = ranges::search(luks_dev, boot_uuid); + if (found.empty()) { + luks_dev = fmt::format("{} cryptdevice=UUID={}:{}", luks_dev, boot_uuid, boot_name); } } @@ -538,9 +577,11 @@ void id_system() noexcept { } bool handle_connection() noexcept { - bool connected{}; + bool connected{utils::is_connected()}; - if (!(connected = utils::is_connected())) { +#ifdef NDEVENV + static constexpr std::int32_t CONNECTION_TIMEOUT = 15; + if (!connected) { warning_inter("An active network connection could not be detected, waiting 15 seconds ...\n"); std::int32_t time_waited{}; @@ -568,7 +609,6 @@ bool handle_connection() noexcept { } } -#ifdef NDEVENV if (connected) { utils::exec("yes | pacman -Sy --noconfirm", true); } diff --git a/src/utils.hpp b/src/utils.hpp index 880d4e9..6ae02b9 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -10,7 +10,7 @@ #include // for vector namespace utils { -void print_banner() noexcept; + [[nodiscard]] bool is_connected() noexcept; bool prompt_char(const char* prompt, const char* color = RESET, char* read = nullptr) noexcept; void clear_screen() noexcept; diff --git a/src/widgets.cpp b/src/widgets.cpp index 4f30a6d..8dd25d9 100644 --- a/src/widgets.cpp +++ b/src/widgets.cpp @@ -137,15 +137,12 @@ void msgbox_widget(const std::string_view& content, Decorator boxsize) noexcept auto button_option = ButtonOption(); button_option.border = false; auto button_back = Button("OK", screen.ExitLoopClosure(), &button_option); - /* clang-format on */ - - auto container = Container::Horizontal({ - button_back, - }); + auto container = Container::Horizontal({button_back}); auto renderer = Renderer(container, [&] { - return centered_widget(container, "New CLI Installer", multiline_text(utils::make_multiline(content.data())) | hcenter | boxsize); + return centered_widget(container, "New CLI Installer", multiline_text(utils::make_multiline(content)) | boxsize); }); + /* clang-format on */ screen.Loop(renderer); } @@ -298,9 +295,10 @@ void radiolist_widget(const std::vector& entries, const std::functi auto radiolist = Container::Vertical({ Radiobox(&entries, selected), }); - auto content = Renderer(radiolist, [&] { + + auto content = Renderer(radiolist, [&] { return radiolist->Render() | center | widget_sizes.content_size; - }); + }); ButtonOption button_option{.border = false}; auto controls_container = controls_widget({"OK", "Cancel"}, {ok_callback, screen->ExitLoopClosure()}, &button_option); @@ -332,4 +330,40 @@ void radiolist_widget(const std::vector& entries, const std::functi 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; + }); + + 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 diff --git a/src/widgets.hpp b/src/widgets.hpp index 9439205..813a0ac 100644 --- a/src/widgets.hpp +++ b/src/widgets.hpp @@ -30,13 +30,14 @@ namespace detail { auto from_vector_checklist(const std::vector& opts, bool* opts_state) noexcept -> ftxui::Components; auto from_checklist_string(const std::vector& opts, bool* opts_state) noexcept -> std::string; auto from_checklist_vector(const std::vector& opts, bool* opts_state) noexcept -> std::vector; - void msgbox_widget(const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; + void msgbox_widget(const std::string_view& content, ftxui::Decorator boxsize = ftxui::hcenter | size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; bool inputbox_widget(std::string& value, const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5), bool password = false) noexcept; void infobox_widget(const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; bool yesno_widget(const std::string_view& content, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; bool yesno_widget(ftxui::Component& container, ftxui::Decorator boxsize = size(ftxui::HEIGHT, ftxui::GREATER_THAN, 5)) noexcept; void menu_widget(const std::vector& entries, const std::function&& ok_callback, std::int32_t* selected, ftxui::ScreenInteractive* screen, const std::string_view& text = "", const WidgetBoxSize widget_sizes = {}) noexcept; void radiolist_widget(const std::vector& entries, const std::function&& ok_callback, std::int32_t* selected, ftxui::ScreenInteractive* screen, const std::string_view& text = "", const WidgetBoxSize widget_sizes = {}) noexcept; + void checklist_widget(const std::vector& opts, const std::function&& ok_callback, bool* opts_state, ftxui::ScreenInteractive* screen, const std::string_view& text = "", const std::string_view& title = "New CLI Installer", const WidgetBoxSize widget_sizes = {}) noexcept; } // namespace detail } // namespace tui