diff --git a/joomer-ftxui-file-browser.cpp b/joomer-ftxui-file-browser.cpp index e69aa6b..b3944ad 100644 --- a/joomer-ftxui-file-browser.cpp +++ b/joomer-ftxui-file-browser.cpp @@ -3,18 +3,16 @@ #include #include #include -#include // Required for std::filesystem +#include -//using namespace std; -//namespace fs = std::filesystem; // Create a shorter alias for std::filesystem - -std::string directory_path = "."; // Replace with your directory path -std::string test; +std::string directory_path = "."; // Note: You must pass the ScreenInteractive object to trigger a redraw. -void ReloadDirectory(ftxui::ScreenInteractive& screen, const std::filesystem::path& new_path, std::vector& entries) { - test = "ReloadDirectory"; - //namespace fs = std::filesystem; +void ReloadDirectory(ftxui::ScreenInteractive& screen, const std::filesystem::path& new_path, std::vector& entries, std::vector& clean_names) { + if (!std::filesystem::exists(new_path) || !std::filesystem::is_directory(new_path)) return; + + entries.clear(); + clean_names.clear(); //std::string directory_path = new_path.string; // Replace with your directory path // linux std::string directory_path = new_path.string(); // Replace with your directory path //windows @@ -22,38 +20,43 @@ void ReloadDirectory(ftxui::ScreenInteractive& screen, const std::filesystem::pa if (!std::filesystem::exists(new_path) || !std::filesystem::is_directory(new_path)) { // Handle error case (optional: display a warning in the TUI) std::cerr << "Error: Not a directory or path does not exist." << std::endl; - test = "path not a directory: " + new_path.string(); + std::cerr << "Path not a directory: " + new_path.string(); return; } // 2. Read the new directory entries int i = 1; - test = "list dir"; + + clean_names.clear(); entries.clear(); - for (const auto& entry : std::filesystem::directory_iterator(new_path)) { - test = "got in for loop, new path is " + new_path.string(); + entries.push_back("0. .. (go up one level)"); // Option to go up one level + clean_names.push_back(".."); + for (const auto& entry : std::filesystem::directory_iterator(new_path)) { + if (std::filesystem::is_directory(entry.path()) || std::filesystem::is_regular_file(entry.path())) { + + std::string name = entry.path().filename().string(); + if (name.starts_with(".")) + continue; // Skip hidden files and directories + entries.push_back(std::to_string(i) + ". " + name); + clean_names.push_back(name); i++; - std::string name = entry.path().filename().string(); - //if (fs::is_directory(entry.path())) { - // name += "/"; - //} - entries.push_back(name); - //entries.push_back(std::to_string(i) + ". " + name); - //actual_paths.push_back(entry.path()); } } } int main(int argc, char* argv[]) { - //using namespace ftxui; - //using namespace std; // Define a variable to hold the final selection index int final_selected_index = -1; // Use -1 to indicate no selection was made std::vector entries; + std::vector clean_names; // New vector for logic + std::string current_path = std::filesystem::current_path().string(); if (argc > 1) + { directory_path = argv[1]; + current_path = directory_path; + } // Check if the directory exists if (!std::filesystem::exists(directory_path) || !std::filesystem::is_directory(directory_path)) { @@ -62,39 +65,61 @@ int main(int argc, char* argv[]) { } auto screen = ftxui::ScreenInteractive::TerminalOutput(); - - - std::filesystem::directory_iterator entryIt(directory_path); - int i = 0; - // Iterate through the directory entries - for (const auto& entry : std::filesystem::directory_iterator(directory_path)) - //for (entryIt = entries.begin(), i = 0; entryIt != entries.end(); ++ entryIt, i++) - { - i++; - std::string str_num = std::to_string(i); - entries.push_back( entry.path().filename().string()); - } - /* = { - "entry 1", - "entry 2", - "entry 3", - };*/ + ReloadDirectory(screen, directory_path, entries, clean_names); + int selected = 0; auto menu = ftxui::Menu({ .entries = &entries, .selected = &selected, }); + std::string input_buffer = ""; // Stores digits as the user types them + // --- The key part: Applying CatchEvent() --- auto menu_with_event_handler = menu | ftxui::CatchEvent([&](ftxui::Event event) { + // 1. Handle Digit Input (0-9) + if (event.is_character()) { + char c = event.character()[0]; + if (std::isdigit(c)) { + input_buffer += c; // Add the digit to our "typing" buffer + //std::cout << "Typed so far: " << input_buffer << std::endl; // For debugging + return true; + } + } + + // 2. Handle Backspace (to correct typing errors) + if (event == ftxui::Event::Backspace && !input_buffer.empty()) { + input_buffer.pop_back(); + return true; + } + // Handle the 'Enter' key press if (event == ftxui::Event::Return) { - // 1. Store the selected index - final_selected_index = selected; - std::cout << "Selected Entry: " << entries[selected] << std::endl; - directory_path = directory_path + "/" + entries[selected]; + if (!input_buffer.empty()) { + // Convert buffer to integer and check bounds + int requested_index = std::stoi(input_buffer);// -1; + if (requested_index >= 0 && requested_index < (int)clean_names.size()) { + selected = requested_index; // Move the highlight to the typed index + } + input_buffer.clear(); // Clear buffer after use + } + std::string selected_name; + std::filesystem::path new_path; + if (clean_names.size() > 0) + selected_name = clean_names[selected]; + // Construct the new path + if (selected_name == "..") { + new_path = std::filesystem::path(current_path).parent_path(); + } + else { + new_path = std::filesystem::path(current_path) / selected_name; + } + new_path.make_preferred(); + current_path = new_path.string(); + // Call the function to switch and reload - ReloadDirectory(screen, directory_path, entries); + ReloadDirectory(screen, new_path, entries,clean_names); + selected = 0; // Reset selection to the first item //screen.Exit(); // Exit the application return true; // Event handled } @@ -110,13 +135,43 @@ int main(int argc, char* argv[]) { return false; }); - screen.Loop(menu_with_event_handler); + // Create a renderer that defines the layout of your application + auto main_renderer = ftxui::Renderer(menu_with_event_handler, [&] { + return ftxui::vbox({ + + // Header showing the current directory + ftxui::hbox({ + ftxui::text(" Current Directory: ") | ftxui::bold, + ftxui::text(current_path) | ftxui::color(ftxui::Color::Cyan), + }), + ftxui::separator(), + + // The menu itself, wrapped in a frame to allow scrolling if the list is long + menu_with_event_handler->Render() | ftxui::vscroll_indicator | ftxui::frame, + + ftxui::filler(), // Pushes the footer to the bottom + ftxui::separator(), + + ftxui::hbox({ + ftxui::text("Enter folder #: "), + ftxui::text(input_buffer), + }), + + // Footer with instructions + ftxui::hbox({ + ftxui::text(" [Enter] Open [q] Quit "), + ftxui::filler(), + ftxui::text(" Items: " + std::to_string(clean_names.size())) | ftxui::dim, + }), + }) | ftxui::border; // Adds a border around the whole app + }); + + screen.Loop(main_renderer); // ---------------------------------------------------- // --- OUTPUT AFTER THE LOOP HAS CLEANLY EXITED --- // ---------------------------------------------------- - std::cout<< "directory path: " << directory_path << std::endl; - //cout << "test: " << test << endl; + std::cout<< "directory path: " << directory_path << std::endl; if (final_selected_index >= 0 && final_selected_index < entries.size()) { std::cout << "Selected Entry: " << entries[final_selected_index] << std::endl; } else {