TwT-6's picture
Upload 2667 files
256a159 verified
raw
history blame
2.78 kB
import sys
if sys.platform == 'win32': # Always return win32 for Windows
# curses is not supported on Windows
# If you want to use this function in Windows platform
# you can try `windows_curses` module by yourself
curses = None
else:
import curses
class Menu:
"""A curses menu that allows the user to select one item from each list.
Args:
lists (list[list[str]]): A list of lists of strings, where each list
represents a list of items to be selected from.
prompts (list[str], optional): A list of prompts to be displayed above
each list. Defaults to None, in which case each list will be
displayed without a prompt.
"""
def __init__(self, lists, prompts=None):
self.choices_lists = lists
self.prompts = prompts or ['Please make a selection:'] * len(lists)
self.choices = []
self.current_window = []
def draw_menu(self, stdscr, selected_row_idx, offset, max_rows):
stdscr.clear()
h, w = stdscr.getmaxyx()
for idx, row in enumerate(self.current_window[offset:offset +
max_rows]):
x = w // 2 - len(row) // 2
y = min(h - 1,
idx + 1) # Ensure y never goes beyond the window height
if idx == selected_row_idx - offset:
stdscr.attron(curses.color_pair(1))
stdscr.addstr(y, x, row)
stdscr.attroff(curses.color_pair(1))
else:
stdscr.addstr(y, x, row)
stdscr.refresh()
def run(self):
curses.wrapper(self.main_loop)
return self.choices
def main_loop(self, stdscr):
curses.curs_set(0)
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
h, w = stdscr.getmaxyx()
max_rows = h - 2
for choices, prompt in zip(self.choices_lists, self.prompts):
self.current_window = [prompt] + choices
current_row_idx = 1
offset = 0
while 1:
self.draw_menu(stdscr, current_row_idx, offset, max_rows)
key = stdscr.getch()
if key == curses.KEY_UP and current_row_idx > 1:
current_row_idx -= 1
if current_row_idx - offset < 1:
offset -= 1
elif key == curses.KEY_DOWN and current_row_idx < len(choices):
current_row_idx += 1
if current_row_idx - offset > max_rows - 1:
offset += 1
elif key == curses.KEY_ENTER or key in [10, 13]:
self.choices.append(choices[current_row_idx - 1])
break