# NOTES: # Look into subclasses # - Report() # - should this be a Menu subclass? # - ReportSummary() & ReportDetail() # - ReportSummary puts a stat in the item fiels like Param does. # - ReportDetail prints new lines with columns and rows on .indicate() # - I do not want to select a report entry. So doesn't need to be an EntryList? # - I would like some connectivity to Param entries that would change the report args from msvcrt import * class Entry(): def __init__(self, text, color_int=7): self.text = text self.color_int = color_int self.select = False @property def text_color(self): if self.color_int > 0 and self.color_int <=7: return f'\033[9{self.color_int}m' @property def indicate_color(self): if self.color_int > 0 and self.color_int <=7: return f'\033[10{self.color_int}m\033[30m' def indicate(self, color_int=None): color = '\033[0m' if self.select and color_int == None: color = f'\033[10{self.color_int}m\033[30m' elif self.select: color = f'\033[10{color_int}m\033[30m' elif not self.select and self.color_int != 7: color = f'\033[9{self.color_int}m' return color + ' ' + self.text + ' ' + '\033[0m' class Launcher(Entry): def __init__(self, text, meth, color_int=7, args_getr_meth=None, *args, **kwargs): super().__init__(text, color_int) self.meth = meth self.color_int = color_int self.args_getr_meth = args_getr_meth self.args = args self.kwargs = kwargs @property def item(self): return self def get_args(self): if self.args_getr_meth != None: self.args = self.args_getr_meth() def launch(self): self.get_args() self.meth(*self.args) # There are Params with a control list to select from # There are Params that use input() # Need to handle boolean values for toggle setting. # I could use existing list functionality passing a list [False, True] # My vision was to display a "box" with brakets and populate with a star [*] for True, [ ] for False. class Param(Entry): def __init__(self, text, init_val=None, color_int=7, itm_color_int=None, setr_meth=None, getr_meth=None): super().__init__(text, color_int) if getr_meth != None: self.options = getr_meth() self.item = self.options[0] elif type(init_val) is list: self.options = init_val self.item = init_val[0] else: self.item = init_val self.edit = False self.itm_color_int = itm_color_int self.setr_meth = setr_meth self.getr_meth = getr_meth def set_item(self, new_val): self.item = new_val if self.setr_meth != None: self.setr_meth(new_val) def get_options(self): if self.getr_meth != None: self.options = self.getr_meth() if not self.item in self.options: self.set_item(self.options[0]) def indicate(self, color_int=None): if self.color_int != 7: txt_clr_i = self.color_int elif color_int != None: txt_clr_i = color_int else: txt_clr_i = self.color_int if self.itm_color_int != None: itm_clr_i = self.itm_color_int else: itm_clr_i = txt_clr_i if self.select and self.edit: txt_color = f'\033[9{txt_clr_i}m' itm_color = f'\033[10{itm_clr_i}m\033[30m\033[s' elif self.select: txt_color = f'\033[10{txt_clr_i}m\033[30m' itm_color = f'\033[9{itm_clr_i}m' else: txt_color = f'\033[9{txt_clr_i}m' itm_color = f'\033[9{itm_clr_i}m' txt = '' if len(self.text) < 6: txt = f'{txt_color} {self.text} \033[0m\t\t' elif len(self.text) >= 6 and len(self.text) < 14: txt = f'{txt_color} {self.text} \033[0m\t' elif len(self.text) >= 14: txt = f'{txt_color} {self.text[0:15]} \033[0m' return f'''{txt}: {itm_color} {str(self.item)} \033[0m''' # Using list indexes is lazy. I really want to "professionalize" the code by using iterator functionality. This would also handle other data types and custom class objects as well. def edit_item(self, next='NEXT'): if next == 'NEXT': next_ind = self.options.index(self.item) + 1 if next_ind > (len(self.options) - 1): next_ind = 0 elif next == 'PREV': next_ind = self.options.index(self.item) - 1 if next_ind < 0: next_ind = len(self.options) - 1 self.set_item(self.options[next_ind]) if self.itm_color_int != None: itm_clr_i = self.itm_color_int else: itm_clr_i = self.color_int itm_color = f'\033[10{itm_clr_i}m\033[30m' print(f'\033[u{itm_color} {self.item} \033[0m', sep='') def keyboard_edit(self): itm_color = f'\033[10{self.color_int}m\033[30m' if hasattr(self, 'options'): self.get_options() while True: cmd = getch() if cmd == b'\x1b' or cmd == b'\x08' or cmd == b'\r': break elif cmd == b'\x00' or cmd == b'\xe0': cmd = getch() if cmd == b'M' or cmd == b'P': self.edit_item('NEXT') elif cmd == b'K' or cmd == b'H': self.edit_item('PREV') elif cmd == b'\t': self.edit_item('NEXT') else: # there are some UI improvements that could be made. you are typing over the old value on the screen. # I don't want it to clear the old value, I want it to wait for a keyboard command before clearing. # if we did that, we'd actually have to print that keystroke and put it in the self.item. new_val = input(f'\033[u{itm_color} ') if new_val: self.set_item(new_val)