terminal_menu/Menu.py
2023-05-27 15:22:47 +02:00

169 lines
6.2 KiB
Python

import os;
import utils
class Menu():
def __init__(self, options: list, title: str = None, cursor: str = "> ", cursor_pos: int = 0, preview_body_function = None, preview_title_function = None, preview_args: list = None, preview_ratio: float = 0.5, circular: bool = True, skip_empty_option: bool = False, quit_button: bool = False):
self.options = options;
self.title = title;
self.cursor = cursor;
self.cursor_pos = cursor_pos;
self.cursor_pos_x = 0;
self.preview_body_function = preview_body_function;
self.preview_title_function = preview_title_function;
if (preview_args == None):
self.preview_args = options;
else:
self.preview_args = preview_args;
self.circular = circular;
self.skip_empty_option = skip_empty_option;
self.size = len(options)
self.preview_ratio = preview_ratio;
def _up(self):
if (self.circular == False):
if (self.cursor_pos != 0):
self.cursor_pos = self.cursor_pos - 1
else:
self.cursor_pos = (self.cursor_pos - 1) % self.size;
if (self.skip_empty_option == True):
if (self.options[self.cursor_pos] == None
or self.options[self.cursor_pos] == ""):
self._up()
self.cursor_pos_x = 0;
def _down(self):
if (self.circular == False):
if (self.cursor_pos != self.size - 1):
self.cursor_pos = self.cursor_pos + 1
else:
self.cursor_pos = (self.cursor_pos + 1) % self.size;
if (self.skip_empty_option == True):
if (self.options[self.cursor_pos] == None
or self.options[self.cursor_pos] == ""):
self._down()
self.cursor_pos_x = 0;
def _left(self):
if (self.cursor_pos_x > 0):
self.cursor_pos_x = self.cursor_pos_x - 1;
def _right(self):
self.cursor_pos_x = self.cursor_pos_x + 1;
def show(self):
while (True):
self._display_menu();
key = self._get_input()
if (key == "up"):
self._up()
elif (key == "down"):
self._down()
if (key == "left"):
self._left()
elif (key == "right"):
self._right()
elif (key == "enter"):
return (self.cursor_pos)
def _display_menu(self):
self._clear();
size = os.get_terminal_size();
size_x = size.columns;
size_y = size.lines - 2;
preview = self._preview();
content_size, preview_size = utils.get_sizes(self.size,
preview.count("\n") + 1,
size_y,
self.preview_ratio)
min_y, max_y, display_pos = utils.render(self.cursor_pos,
0,
self.size,
content_size // 2,
self.options)
for i, option in enumerate(self.options[min_y:max_y]):
element = option
if (i == display_pos):
min_x, max_x, display_pos_x = utils.render(self.cursor_pos_x,
0,
len(element),
len(element) // 2,
option)
line = self.cursor + element[min_x:max_x]
else:
line = " " * len(self.cursor) + element
print(line)
print(preview)
def _preview(self):
if (len(self.preview_args) < self.cursor_pos):
return
title = ""
if (self.preview_title_function != None):
title = self.preview_title_function(self.preview_args[self.cursor_pos])
elif (self.preview_body_function != None):
body = self.preview_body_function(self.preview_args[self.cursor_pos])
return (title + "\n" + body);
def _clear(self):
os.system("clear")
def _get_input(self) -> str:
flag_have_getch = False
flag_have_msvcrt = False
try :
import getch
flag_have_getch = True
first_char = getch.getch()
if first_char == '\x1b': #arrow keys
a=getch.getch()
b=getch.getch()
return {'[A': 'up', '[B': 'down', '[C': 'right', '[D': 'left' }[a+b]
if ord(first_char) == 10:
return 'enter'
if ord(first_char) == 32:
return 'space'
else:
return first_char #normal keys like abcd 1234
except :
pass
try:
import msvcrt
flag_have_msvcrt = True
key = msvcrt.getch() # get keypress
if key == b'\x1b': # Esc key to exit
return 'esc'
elif key == b'\r': # Enter key to select
return 'enter'
elif key == b'\x48': # Up or Down arrow
return 'up'
elif key == b'\x50': # Up or Down arrow
return 'down'
else:
return key.decode('utf-8')
except:
pass
if flag_have_getch == False and flag_have_msvcrt == False:
print('\nErr:\tcan\'t get input \nFix:\tpip install getch')
exit()
first_char = getch.getch()
print (first_char)
if first_char == '\x1b': #arrow keys
a=getch.getch()
b=getch.getch()
return {'[A': 'up', '[B': 'down', '[C': 'right', '[D': 'left' }[a+b]
if ord(first_char) == 10:
return 'enter'
if ord(first_char) == 32:
return 'space'
def preview(lst):
return ("je suis la")
menu = Menu("fdddddddddddddddddddddddddddddddddddddddddddddddddddddddda", preview_body_function=preview);
menu.show()