Skip to content

Instantly share code, notes, and snippets.

@louisswarren
Last active March 7, 2020 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save louisswarren/73480bb788404e86f0a069fc62d85245 to your computer and use it in GitHub Desktop.
Save louisswarren/73480bb788404e86f0a069fc62d85245 to your computer and use it in GitHub Desktop.
Menus with curses in python
import curses
class Menu:
def __init__(self, y, x, options):
self.y = y
self.x = x
self.options = options
self.height = len(options)
self.width = max(len(opt) for opt in options)
self.win = curses.newwin(self.height + 2, self.width + 8, y, x)
self.sel = 0
self.optfmt = f' | {{:<{self.width}s}} | '
def draw(self):
self.win.addstr(0, 0, ' /--' + '-' * self.width + '--\\ ')
for i, opt in enumerate(self.options):
self.win.addstr(i + 1, 0, self.optfmt.format(opt))
self.win.addstr(self.height + 1, 0, ' \\--' + '-' * self.width + '--/')
self.win.addstr(self.sel + 1, 0, '==> ')
def setsel(self, n):
self.win.addstr(self.sel + 1, 0, ' | ')
self.sel = n
self.win.addstr(self.sel + 1, 0, '==> ')
def getsel(self):
while (key := self.win.getkey()) not in ('f', '\n'):
if key == 'k':
self.setsel((self.sel - 1) % self.height)
self.win.refresh()
if key == 'j':
self.setsel((self.sel + 1) % self.height)
self.win.refresh()
if key == 'a':
return None
return self.options[self.sel]
def refresh(self):
return self.win.refresh()
def clear(self):
return self.win.clear()
def tree_menu_sel(y, x, options_tree):
def get_title(opt):
if isinstance(opt, str):
return opt
else:
return opt[0]
m = Menu(y, x, [get_title(opt) for opt in options_tree])
m.draw()
m.refresh()
while True:
sel = m.getsel()
if sel is None:
m.clear()
m.refresh()
return None
for i, optx in enumerate(options_tree):
if isinstance(optx, str):
title = optx
subtree = None
else:
title, subtree = optx
if sel == title:
if not subtree:
return sel,
else:
r = tree_menu_sel(y + i, x + m.width + 5, subtree)
if r:
return (sel,) + r
else:
m.draw()
m.refresh()
break
def main(stdscr):
curses.curs_set(False)
stdscr.clear()
stdscr.addstr("Hello!")
stdscr.refresh()
# m = Menu(7, 20, ("Say hello", "Say goodbye", "Exit"))
# m.draw()
# m.refresh()
# sel = m.getsel()
sel = tree_menu_sel(7, 20, (("Say hello",
("To Alice", "To Bob")),
("Say goodbye",
("Loudly",
("Quietly",
("To Alice", "To Bob")))),
"Exit"))
stdscr.addstr("\n" + " > ".join(sel))
stdscr.getkey()
if __name__ == '__main__':
curses.wrapper(main)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment