X-Git-Url: https://git.armaanb.net/?a=blobdiff_plain;f=lightcards%2Fdisplay.py;h=940d15efadae8e254c3e14a722ed0dd85a075ecd;hb=8413a396838f01c3bd87876bcf4e5e94a65ba0d2;hp=a707fc15950244939afda2c206f6fe38c9afddb5;hpb=9a03674645c2535cadedf2dc077ad7303e434435;p=lightcards.git diff --git a/lightcards/display.py b/lightcards/display.py old mode 100755 new mode 100644 index a707fc1..940d15e --- a/lightcards/display.py +++ b/lightcards/display.py @@ -6,190 +6,254 @@ from random import shuffle import sys import textwrap +from . import lightcards -def disp_bar(stdscr, stack, headers, obj): - """ - Display the statusbar at the bottom of the screen with progress, star - status, and card side. - """ - (mlines, mcols) = stdscr.getmaxyx() - - # Calculate percent done - if len(stack) <= 1: - percent = "100" - else: - percent = str(round(obj.getIdx() / (len(stack) - 1) * 100)).zfill(3) - - # Put all the info together - stdscr.insstr(mlines - 1, 0, - "[" + - stack[obj.getIdx()].printStar() + - "] [" + - percent + - "% (" + - str(obj.getIdx() + 1).zfill(len(str(len(stack)))) + - "/" + - str(len(stack)) + - ")]" + - " [" + - headers[obj.getSide()] + - " (" + - str(obj.getSide() + 1) + - ")]", curses.color_pair(1)) - - -def disp_menu(stdscr, stack, headers, idx): - """ - Display a menu once the end of the deck has been reached, offering - multiple options on how to continue. - """ - stdscr.addstr("Good job, you've completed a round!\n\n", - curses.color_pair(1)) - stdscr.addstr("Choose one of the following options:\n" + - "[r]: restart\n" + - "[s]: restart with starred only\n" + - "[u]: restart and unstar all\n" + - "[z]: restart and shuffle cards\n" + - "[q]: quit") - while True: - key = stdscr.getkey() - if key == "q": - sys.exit(0) - elif key == "r": - idx.setIdx(0) - get_key(stdscr, stack, headers, idx) - elif key == "u": - idx.setIdx(0) - for x in stack: - x.unStar() - get_key(stdscr, stack, headers, idx) - elif key == "s": - # Check if there are any starred cards before proceeding, and if - # not, don't allow to proceed and show an error message - cont = False - for x in stack: - if x.getStar(): - cont = True - - if cont: - idx.setIdx(0) - stack = [x for x in stack if x.getStar()] - get_key(stdscr, stack, headers, idx) - else: - stdscr.clear() - stdscr.addstr("ERR: Stack empty. Choose another option\n\n", - curses.color_pair(2)) - disp_menu(stdscr, stack, headers, idx) - elif key == "z": - idx.setIdx(0) - shuffle(stack) - get_key(stdscr, stack, headers, idx) - - -def disp_card(stdscr, stack, headers, obj): - """ - Display the contents of the card - Shows a header, a horizontal line, and the contents of the current side. - """ - stdscr.clear() - (mlines, mcols) = stdscr.getmaxyx() - if obj.getIdx() == len(stack): - disp_menu(stdscr, stack, headers, obj) - else: - # If on the back of the card, show the content of the front side in the - # header - num_done = str(obj.getIdx() + 1).zfill(len(str(len(stack)))) - if obj.getSide() == 0: - top = num_done + " | " + headers[obj.getSide()] + +class Display(): + def __init__(self, stack, headers, obj): + self.stack = stack + self.headers = headers + self.obj = obj + + def run(self, stdscr): + self.win = stdscr + curses.curs_set(0) # Hide cursor + curses.init_pair(1, curses.COLOR_CYAN, 0) + curses.init_pair(2, curses.COLOR_RED, 0) + curses.init_pair(3, curses.COLOR_YELLOW, 0) + self.get_key() + + def disp_bar(self): + """ + Display the statusbar at the bottom of the screen with progress, star + status, and card side. + """ + (mlines, mcols) = self.win.getmaxyx() + + # Calculate percent done + if len(self.stack) <= 1: + percent = "100" else: - top = num_done + " | " + headers[obj.getSide()] + " | \"" + \ - str(stack[obj.getIdx()][0]) + "\"" - header_width = mcols - if mcols > 80: - header_width = 80 + percent = str(round(self.obj.getIdx() / + len(self.stack) * 100)).zfill(2) + + # Print yellow if starred + if self.stack[self.obj.getIdx()].getStar(): + star_color = curses.color_pair(3) + else: + star_color = curses.color_pair(1) + + # Create bar component + bar_start = "[" + bar_middle = self.stack[self.obj.getIdx()].printStar() + bar_end = "] [" + percent + "% (" + \ + str(self.obj.getIdx() + 1).zfill(len(str(len(self.stack)))) + \ + "/" + str(len(self.stack)) + ")] [" + \ + self.headers[self.obj.getSide()] + " (" + \ + str(self.obj.getSide() + 1) + ")]" + + # Put it all togethor + self.win.addstr(mlines - 1, 0, bar_start, curses.color_pair(1)) + self.win.addstr(bar_middle, star_color) + self.win.insstr(bar_end, curses.color_pair(1)) + + def menu_print(self, string, err=False): + (mlines, mcols) = self.win.getmaxyx() + self.win.clear() + if err: + color = curses.color_pair(2) + else: + color = curses.color_pair(1) + self.disp_menu(keygrab=False) + self.win.addstr("\n\n" + string, color) + self.menu_grab() - stdscr.addstr(textwrap.shorten(top, width=header_width, - placeholder="…"), curses.A_BOLD) + def menu_grab(self): + while True: + key = self.win.getkey() + if key == "q": + if len(self.stack) == self.obj.getIdx(): + sys.exit(0) + elif len(self.stack) < self.obj.getIdx(): + self.obj.setIdx(0) + self.get_key() + elif key == "y": + self.stack = lightcards.get_orig()[1] + self.menu_print("Stack reset!") + elif key == "u": + [x.unStar() for x in self.stack] + self.menu_print("All unstarred!") + elif key == "d": + [x.star() for x in self.stack] + self.menu_print("All starred!") + elif key == "t": + self.stack.reverse() + self.menu_print( + "self.stack reversed!") + elif key == "z": + shuffle(self.stack) + self.menu_print("Stack shuffled!") + elif key == "f": + for x in self.stack: + x[0], x[1] = x[1], x[0] + (self.headers[0], self.headers[1]) = (self.headers[1], + self.headers[0]) + self.menu_print("Cards flipped!") + elif key == "s": + # Check if there are any starred cards before proceeding, and + # if not, don't allow to proceed and show an error message + cont = False + for x in self.stack: + if x.getStar(): + cont = True + break - # Add horizontal line - lin_width = header_width - if len(top) < header_width: - lin_width = len(top) - stdscr.hline(1, 0, curses.ACS_HLINE, lin_width) + if cont: + self.stack = [x for x in self.stack if x.getStar()] + self.menu_print("Stars only!") + else: + self.menu_print("ERR: None are starred!", err=True) + elif key in ["h", "KEY_LEFT"]: + self.obj.setIdx(len(self.stack) - 1) + self.get_key() + elif key == "r": + self.obj.setIdx(0) + self.get_key() - # Show current side + def disp_menu(self, keygrab=True): + """ + Display a menu once the end of the deck has been reached, offering + multiple options on how to continue. + """ + + self.win.addstr("LIGHTCARDS MENU", curses.color_pair(1) + + curses.A_BOLD) + self.win.hline(1, 0, curses.ACS_HLINE, 15) + self.win.addstr(2, 0, "[y]: reset stack to original state\n" + + "[z]: shuffle stack\n" + + "[f]: flip all cards in stack\n" + + "[t]: reverse stack order\n" + + "[u]: unstar all\n" + + "[d]: star all\n" + + "[s]: update stack to include starred only\n\n" + + "[r]: restart\n" + + "[q]: back") + + if keygrab: + self.menu_grab() + + def wrap_width(self): + (mlines, mcols) = self.win.getmaxyx() wrap_width = mcols if mcols > 80: wrap_width = 80 - stdscr.addstr(2, 0, textwrap.fill(stack[obj.getIdx()][obj.getSide()], - width=wrap_width)) - disp_bar(stdscr, stack, headers, obj) - - -def disp_help(stdscr, stack, headers, idx): - """Display help screen""" - stdscr.clear() - stdscr.addstr("LIGHTCARDS HELP", curses.color_pair(1) + curses.A_BOLD) - stdscr.hline(1, 0, curses.ACS_HLINE, 15) - stdscr.addstr(2, 0, - "Welcome to lightcards. Here are some keybindings to get\n" + - "you started.\n\n" + - "h, left previous card\n" + - "l, right next card\n" + - "j, k, up, down flip card\n" + - "i, / star card\n" + - "0, ^, home go to the start of the deck\n" + - "$, end go to the end of the deck\n" + - "H, ? open this screen\n\n" + - "More information can be found in the man page, or by\n" + - "running `lightcards --help`.\n\n" + - "Press [q], [H], or [?] to go back.") - while True: - key = stdscr.getkey() - if key in ["q", "H", "?"]: - get_key(stdscr, stack, headers, idx) - - -def init_disp(stdscr, stack, headers, idx): - """Initialize curses options. Entrypoint into the display functions.""" - curses.curs_set(0) # Hide cursor - curses.init_pair(1, curses.COLOR_CYAN, 0) - curses.init_pair(2, curses.COLOR_RED, 0) - get_key(stdscr, stack, headers, idx) - - -def get_key(stdscr, stack, headers, idx): - """ - Display a card and wait for the input. - Used as a general way of getting back into the card flow from a menu - """ - - disp_card(stdscr, stack, headers, idx) - while True: - key = stdscr.getkey() - if key == "q": - sys.exit(0) - elif key in ["l", "KEY_LEFT"]: - idx.forward(stack) - idx.setSide(0) - disp_card(stdscr, stack, headers, idx) - elif key in ["h", "KEY_RIGHT"]: - idx.back() - idx.setSide(0) - disp_card(stdscr, stack, headers, idx) - elif key in ["j", "k", "KEY_UP", "KEY_DOWN"]: - idx.flip() - disp_card(stdscr, stack, headers, idx) - elif key in ["i", "/"]: - stack[idx.getIdx()].toggleStar() - disp_card(stdscr, stack, headers, idx) - elif key in ["0", "^", "KEY_HOME"]: - idx.setIdx(0) - idx.setSide(0) - disp_card(stdscr, stack, headers, idx) - elif key in ["$", "KEY_END"]: - idx.setIdx(len(stack) - 1) - idx.setSide(0) - disp_card(stdscr, stack, headers, idx) - elif key in ["H", "?"]: - disp_help(stdscr, stack, headers, idx) + return wrap_width + + def disp_card(self): + """ + Display the contents of the card + Shows a header, a horizontal line, and the contents of the current + side. + """ + self.win.clear() + (mlines, mcols) = self.win.getmaxyx() + if self.obj.getIdx() == len(self.stack): + self.disp_menu() + else: + # If on the back of the card, show the content of the front side in + # the header + num_done = str(self.obj.getIdx() + + 1).zfill(len(str(len(self.stack)))) + if self.obj.getSide() == 0: + top = num_done + " | " + self.headers[self.obj.getSide()] + else: + top = num_done + " | " + self.headers[self.obj.getSide()] + \ + " | \"" + str(self.stack[self.obj.getIdx()][0]) + "\"" + header_width = mcols + if mcols > 80: + header_width = 80 + + self.win.addstr(textwrap.shorten(top, width=header_width, + placeholder="…"), curses.A_BOLD) + + # Add horizontal line + lin_width = header_width + if len(top) < header_width: + lin_width = len(top) + self.win.hline(1, 0, curses.ACS_HLINE, lin_width) + + # Show current side + self.win.addstr(2, 0, textwrap.fill( + self.stack[self.obj.getIdx()][self.obj.getSide()], + width=self.wrap_width())) + self.disp_bar() + + def disp_help(self): + """Display help screen""" + self.win.clear() + self.win.addstr("LIGHTCARDS HELP", curses.color_pair(1) + + curses.A_BOLD) + self.win.hline(1, 0, curses.ACS_HLINE, 15) + self.win.addstr(2, 0, textwrap.fill( + "Welcome to lightcards. Here are some keybindings to get you " + + "started:", width=self.wrap_width()) + + "\n\nh, left previous card\n" + + "l, right next card\n" + + "j, k, up, down flip card\n" + + "i, / star card\n" + + "0, ^, home go to the start of the deck\n" + + "$, end go to the end of the deck\n" + + "H, ? open this screen\n" + + "e open the input file in $EDITOR\n" + + "m open the control menu\n\n" + + textwrap.fill( + "More information can be found in the man page, " + + "or by running `lightcards --help`.", + width=self.wrap_width()) + + "\n\nPress [q], [H], or [?] to go back.") + while True: + key = self.win.getkey() + if key in ["q", "H", "?"]: + self.get_key() + + def get_key(self): + """ + Display a card and wait for the input. + Used as a general way of getting back into the card flow from a menu + """ + + self.disp_card() + while True: + key = self.win.getkey() + if key == "q": + sys.exit(0) + elif key in ["l", "KEY_RIGHT"]: + self.obj.forward(self.stack) + self.obj.setSide(0) + self.disp_card() + elif key in ["h", "KEY_LEFT"]: + self.obj.back() + self.obj.setSide(0) + self.disp_card() + elif key in ["j", "k", "KEY_UP", "KEY_DOWN"]: + self.obj.flip() + self.disp_card() + elif key in ["i", "/"]: + self.stack[self.obj.getIdx()].toggleStar() + self.disp_card() + elif key in ["0", "^", "KEY_HOME"]: + self.obj.setIdx(0) + self.obj.setSide(0) + self.disp_card() + elif key in ["$", "KEY_END"]: + self.obj.setIdx(len(self.stack) - 1) + self.obj.setSide(0) + self.disp_card() + elif key in ["H", "?"]: + self.disp_help() + elif key == "m": + self.win.clear() + self.disp_menu() + elif key == "e": + (self.headers, self.stack) = lightcards.reparse() + self.get_key()