1
0
mirror of https://github.com/Foltik/dotfiles synced 2024-11-30 14:32:08 -05:00
dotfiles/lib/menu.py

146 lines
3.9 KiB
Python
Raw Normal View History

2018-10-16 22:02:11 -04:00
import curses
from curses import panel
2018-12-06 01:30:41 -05:00
from types import LambdaType
2018-10-16 22:02:11 -04:00
2018-10-17 01:03:27 -04:00
class BaseMenu:
def __init__(self, stdscreen):
2018-10-16 22:02:11 -04:00
self.window = stdscreen.subwin(0, 0)
self.window.keypad(1)
self.panel = panel.new_panel(self.window)
self.panel.hide()
panel.update_panels()
2018-10-17 01:03:27 -04:00
def up(self):
2018-10-16 22:02:11 -04:00
self.panel.top()
self.panel.show()
self.window.clear()
2018-10-17 01:03:27 -04:00
def down(self):
self.window.clear()
self.panel.hide()
panel.update_panels()
curses.doupdate()
2018-10-16 22:02:11 -04:00
2018-10-17 01:03:27 -04:00
def update(self):
self.window.refresh()
curses.doupdate()
2018-10-16 22:02:11 -04:00
2018-10-17 01:03:27 -04:00
class Menu(BaseMenu):
2018-12-06 01:30:41 -05:00
def __init__(self, stdscreen, title, items):
2018-10-17 01:03:27 -04:00
super().__init__(stdscreen)
self.should_exit = False
self.position = 0
2018-12-06 01:30:41 -05:00
self.title = title
2018-10-17 01:03:27 -04:00
self.items = items
2018-12-06 01:30:41 -05:00
self.items.append(('Exit', self.exit))
2018-10-16 22:02:11 -04:00
2018-10-17 01:03:27 -04:00
def exit(self):
self.should_exit = True
2018-10-16 22:02:11 -04:00
2018-10-17 01:03:27 -04:00
def navigate(self, offset):
self.position += offset
self.position %= len(self.items)
2018-10-16 22:02:11 -04:00
2018-12-06 01:30:41 -05:00
def draw_title(self):
self.window.addstr(1, 1, self.title, curses.A_BOLD)
2018-10-17 01:03:27 -04:00
def draw(self):
2018-12-06 01:30:41 -05:00
self.draw_title()
2018-10-17 01:03:27 -04:00
for index, item in enumerate(self.items):
text = '%d. %s' % (index + 1, item[0])
text_mode = curses.A_REVERSE if index == self.position else curses.A_NORMAL
2018-12-06 01:30:41 -05:00
self.window.addstr(index + 3, 1, text, text_mode)
2018-10-16 22:02:11 -04:00
2018-12-06 01:30:41 -05:00
def select(self, index):
self.items[index][1]()
def input(self, key):
# ESC to quit
if key == 27:
self.window.nodelay(True)
key = self.window.getch()
if key == -1:
return self.exit()
2018-10-16 22:02:11 -04:00
2018-12-06 01:30:41 -05:00
# q to quit
if key == ord('q'):
return self.exit()
# Enter to select item
if key in [curses.KEY_ENTER, ord('\n')]:
self.select(self.position)
2018-10-17 01:03:27 -04:00
2018-12-06 01:30:41 -05:00
# Number keys to select item
if key - ord('0') in range(1, len(self.items) + 1):
self.select(key - ord('0') - 1)
2018-10-17 01:03:27 -04:00
2018-12-06 01:30:41 -05:00
# Arrow keys or jk to navigate
if key in [curses.KEY_UP, ord('k')]:
2018-10-17 01:03:27 -04:00
self.navigate(-1)
2018-12-06 01:30:41 -05:00
elif key in [curses.KEY_DOWN, ord('j')]:
2018-10-17 01:03:27 -04:00
self.navigate(1)
def display(self):
self.up()
while not self.should_exit:
self.update()
self.draw()
2018-12-06 01:30:41 -05:00
key = self.window.getch()
self.input(key)
2018-10-17 01:03:27 -04:00
self.should_exit = False
self.down()
2018-12-06 01:30:41 -05:00
class ChecklistMenu(Menu):
def __init__(self, stdscreen, title, items, default):
super().__init__(stdscreen, title, items)
self.states = [default] * len(items)
def draw(self):
self.draw_title()
for index, item in enumerate(self.items):
text = ''
if isinstance(item[1], LambdaType):
text = '%d. [ %s ] %s' % (index + 1, '*' if self.states[index] else ' ', item[0])
else:
text = '%d. %s' % (index + 1, item[0])
text_mode = curses.A_REVERSE if index == self.position else curses.A_NORMAL
self.window.addstr(index + 3, 1, text, text_mode)
2018-12-08 23:46:22 -05:00
def all(self, val):
for i in range(0, len(self.states)):
self.states[i] = val
for item in self.items:
fn = item[1]
if isinstance(fn, LambdaType):
fn(val)
2018-12-06 01:30:41 -05:00
def input(self, key):
super().input(key)
if key == ord('\t'):
self.expand(self.position)
2018-12-08 23:46:22 -05:00
if key == ord('e'):
self.all(True)
if key == ord('d'):
self.all(False)
2018-12-06 01:30:41 -05:00
def expand(self, index):
if len(self.items[index]) >= 3:
self.items[index][2]()
def select(self, index):
self.states[index] = not self.states[index]
fn = self.items[index][1]
if isinstance(fn, LambdaType):
fn(self.states[index])
else:
fn()