This commit is contained in:
Your Name 2025-04-22 20:01:59 +12:00
parent 4117b3daaf
commit 6a381b539c

View File

@ -21,11 +21,12 @@ int fullscreen_window::ncurses_streambuf::overflow(int c) {
}
fullscreen_window::fullscreen_window(std::string title) {
// Initialize ncurses
initscr();
cbreak();
raw(); // Use raw mode for better control
noecho();
keypad(stdscr, TRUE);
curs_set(0);
keypad(stdscr, TRUE); // Enable keypad
curs_set(0); // Hide cursor
refresh();
// Create display window (takes up all but bottom 4 lines)
@ -33,11 +34,13 @@ fullscreen_window::fullscreen_window(std::string title) {
getmaxyx(stdscr, max_y, max_x);
display_win = newwin(max_y - 4, max_x, 0, 0);
scrollok(display_win, TRUE);
keypad(display_win, TRUE); // Enable keypad for display window
wrefresh(display_win);
// Create input window (bottom 4 lines)
input_win = newwin(4, max_x, max_y - 4, 0);
box(input_win, 0, 0);
keypad(input_win, TRUE); // Enable keypad for input window
wrefresh(input_win);
// Set up output redirection
@ -138,6 +141,9 @@ std::string fullscreen_window::set_input_multiple_choice(std::string prompt, std
std::string filter = "";
auto last_key_time = std::chrono::steady_clock::now();
int scroll_offset = 0;
std::vector<std::string> last_filtered_choices;
int last_selected = -1;
int last_scroll_offset = -1;
while (true) {
// Filter choices based on input
@ -153,12 +159,6 @@ std::string fullscreen_window::set_input_multiple_choice(std::string prompt, std
filter = "";
}
// Calculate total width needed
int total_width = 0;
for (const auto& choice : filtered_choices) {
total_width += choice.length() + 3; // +3 for " | " separator
}
// Get window dimensions
int max_y, max_x;
getmaxyx(input_win, max_y, max_x);
@ -179,76 +179,104 @@ std::string fullscreen_window::set_input_multiple_choice(std::string prompt, std
}
}
// Display filtered choices horizontally
int x = 2 - scroll_offset;
for (size_t i = 0; i < filtered_choices.size(); i++) {
if (i == selected) {
wattron(input_win, A_REVERSE);
}
// Only redraw if something changed
if (filtered_choices != last_filtered_choices ||
selected != last_selected ||
scroll_offset != last_scroll_offset) {
// Only draw if visible
if (x + filtered_choices[i].length() > 0 && x < max_x - 2) {
mvwprintw(input_win, 2, x, "%s", filtered_choices[i].c_str());
}
// Clear the input window except for the prompt
werase(input_win);
box(input_win, 0, 0);
mvwprintw(input_win, 1, 2, "%s", prompt.c_str());
if (i == selected) {
wattroff(input_win, A_REVERSE);
}
// Display filtered choices horizontally
int x = 2 - scroll_offset;
for (size_t i = 0; i < filtered_choices.size(); i++) {
if (i == selected) {
wattron(input_win, A_REVERSE);
}
x += filtered_choices[i].length() + 3; // +3 for " | " separator
// Only draw if visible
if (x + filtered_choices[i].length() > 0 && x < max_x - 2) {
mvwprintw(input_win, 2, x, "%s", filtered_choices[i].c_str());
}
// Draw separator if not last item
if (i < filtered_choices.size() - 1) {
if (x - 3 + 3 > 0 && x - 3 < max_x - 2) {
mvwprintw(input_win, 2, x - 3, " | ");
if (i == selected) {
wattroff(input_win, A_REVERSE);
}
x += filtered_choices[i].length() + 3; // +3 for " | " separator
// Draw separator if not last item
if (i < filtered_choices.size() - 1) {
if (x - 3 + 3 > 0 && x - 3 < max_x - 2) {
mvwprintw(input_win, 2, x - 3, " | ");
}
}
}
}
wrefresh(input_win);
wrefresh(input_win);
// Update last state
last_filtered_choices = filtered_choices;
last_selected = selected;
last_scroll_offset = scroll_offset;
}
int ch = wgetch(input_win);
// Handle key input
if (ch == '\n') {
if (!filtered_choices.empty()) {
return filtered_choices[selected];
}
} else if (ch == 27) { // ESC key
if (!filter.empty()) {
// Clear the filter and reset selection
filter = "";
selected = 0;
scroll_offset = 0;
} else {
// Only return if filter is already empty
return "";
}
} else if (ch == KEY_LEFT || ch == KEY_UP) {
if (selected > 0) {
selected--;
} else {
selected = filtered_choices.size() - 1; // Wrap to end
}
continue; // Skip the rest of the loop
} else if (ch == KEY_RIGHT || ch == KEY_DOWN) {
if (selected < filtered_choices.size() - 1) {
selected++;
} else {
selected = 0; // Wrap to beginning
}
continue; // Skip the rest of the loop
} else if (isprint(ch)) {
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_key_time).count();
switch (ch) {
case '\n':
if (!filtered_choices.empty()) {
return filtered_choices[selected];
}
break;
if (elapsed > 500) { // Reset filter if too much time has passed
filter = "";
}
case 27: // ESC key
if (!filter.empty()) {
// Clear the filter and reset selection
filter = "";
selected = 0;
scroll_offset = 0;
} else {
// Only return if filter is already empty
return "";
}
break;
filter += ch;
selected = 0;
last_key_time = now;
case KEY_LEFT:
case KEY_UP:
if (selected > 0) {
selected--;
} else {
selected = filtered_choices.size() - 1; // Wrap to end
}
break;
case KEY_RIGHT:
case KEY_DOWN:
if (selected < filtered_choices.size() - 1) {
selected++;
} else {
selected = 0; // Wrap to beginning
}
break;
default:
if (isalnum(ch)) {
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_key_time).count();
if (elapsed > 500) { // Reset filter if too much time has passed
filter = "";
}
filter += ch;
selected = 0;
last_key_time = now;
}
break;
}
}
}