From de50a30d6a18dc6fdf2207c49c0370820b9acc1f Mon Sep 17 00:00:00 2001 From: Armaan Bhojwani Date: Sun, 31 Jan 2021 16:57:16 -0500 Subject: [PATCH] Complete restructure of display.py Instead of passing around the same 4 variables, just put everything in a class. Required *extensive* modifications --- lightcards/display.py | 434 ++++++++++++++++++++------------------- lightcards/lightcards.py | 7 +- 2 files changed, 227 insertions(+), 214 deletions(-) diff --git a/lightcards/display.py b/lightcards/display.py index d6d8de2..7e09cdc 100755 --- a/lightcards/display.py +++ b/lightcards/display.py @@ -9,220 +9,230 @@ 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) - - # Print yellow if starred - stdscr.addstr(mlines - 1, 0, "[", curses.color_pair(1)) - if stack[obj.getIdx()].getStar(): - stdscr.addstr(stack[obj.getIdx()].printStar(), curses.color_pair(3)) - else: - stdscr.addstr(stack[obj.getIdx()].printStar(), curses.color_pair(1)) - - # Put all the info together - stdscr.addstr("] [" + - 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. - """ - def menu_print(stdscr, stack, headers, idx, string, err=False): - stdscr.clear() - if err: - stdscr.addstr(string + "\n\n", curses.color_pair(2)) +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: - stdscr.addstr(string + "\n\n", curses.color_pair(1)) - disp_menu(stdscr, stack, headers, idx) - - stdscr.addstr("Choose one of the following options:\n\n" + - "[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" + - "[s]: update stack to include starred only\n\n" + - "[r]: restart\n" + - "[q]: quit") - idx.setIdx(0) - while True: - key = stdscr.getkey() - if key == "q": - sys.exit(0) - elif key == "y": - stack = lightcards.get_orig()[1] - menu_print(stdscr, stack, headers, idx, - "Stack reset!") - elif key == "u": - [x.unStar() for x in stack] - menu_print(stdscr, stack, headers, idx, - "All unstarred!") - elif key == "t": - stack.reverse() - menu_print(stdscr, stack, headers, idx, - "Stack reversed!") - elif key == "z": - shuffle(stack) - menu_print(stdscr, stack, headers, idx, - "Stack shuffled!") - elif key == "f": - for x in stack: - x[0], x[1] = x[1], x[0] - headers[0], headers[1] = headers[1], headers[0] - menu_print(stdscr, stack, headers, idx, - "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 stack: - if x.getStar(): - cont = True - break - - if cont: - stack = [x for x in stack if x.getStar()] - menu_print(stdscr, stack, headers, idx, - "Stars only!") - else: - menu_print(stdscr, stack, headers, idx, - "ERR: None are starred!", - err=True) - elif key == "r": - 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()] + percent = str(round(self.obj.getIdx() / + (len(self.stack) - 1) * 100)).zfill(3) + + # Print yellow if starred + self.win.addstr(mlines - 1, 0, "[", curses.color_pair(1)) + if self.stack[self.obj.getIdx()].getStar(): + self.win.addstr(self.stack[self.obj.getIdx()].printStar(), + curses.color_pair(3)) else: - top = num_done + " | " + headers[obj.getSide()] + " | \"" + \ - str(stack[obj.getIdx()][0]) + "\"" - header_width = mcols - if mcols > 80: - header_width = 80 - - stdscr.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) - stdscr.hline(1, 0, curses.ACS_HLINE, lin_width) - - # Show current side + self.win.addstr(self.stack[self.obj.getIdx()].printStar(), + curses.color_pair(1)) + + # Put all the info together + self.win.addstr("] [" + + 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) + + ")]", curses.color_pair(1)) + + def menu_print(self, string, err=False): + self.win.clear() + if err: + self.win.addstr(string + "\n\n", curses.color_pair(2)) + else: + self.win.addstr(string + "\n\n", curses.color_pair(1)) + self.disp_menu() + + def disp_menu(self): + """ + Display a menu once the end of the deck has been reached, offering + multiple options on how to continue. + """ + + self.win.addstr("Choose one of the following options:\n\n" + + "[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" + + "[s]: update stack to include starred only\n\n" + + "[r]: restart\n" + + "[q]: quit") + self.obj.setIdx(0) + while True: + key = self.win.getkey() + if key == "q": + sys.exit(0) + 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 == "t": + self.stack.reverse() + self.menu_print( + "self.stack reversed!") + elif key == "z": + shuffle(self.stack) + self.menu_print("self.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 + + 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 == "r": + self.get_key() + + 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" + - "e open the input file in $EDITOR\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) - curses.init_pair(3, curses.COLOR_YELLOW, 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) - elif key == "e": - (headers, stack) = lightcards.reparse() - get_key(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\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_LEFT"]: + self.obj.forward(self.stack) + self.obj.setSide(0) + self.disp_card() + elif key in ["h", "KEY_RIGHT"]: + 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 == "e": + (self.headers, self.stack) = lightcards.reparse() + self.get_key() diff --git a/lightcards/lightcards.py b/lightcards/lightcards.py index 779f347..ced97c4 100755 --- a/lightcards/lightcards.py +++ b/lightcards/lightcards.py @@ -8,7 +8,8 @@ import os from random import shuffle import sys -from . import display, parse +from . import parse +from .display import Display from .deck import Status @@ -47,7 +48,9 @@ def show(args, stack, headers): shuffle(stack) elif args.reverse: stack.reverse() - wrapper(display.init_disp, stack, headers, idx) + + win = Display(stack, headers, idx) + wrapper(win.run) def reparse(): -- 2.39.2