Source code for consolemenu.menu_component

try:
    import ansiwrap as textwrap
except ImportError:
    import textwrap

from consolemenu.format import MenuStyle


def ansilen(s):
    """
    Return the length of the string minus any ANSI control codes.
    Args:
        s (string): The input string to check.
    Returns:
        int: The string length.
    """
    if hasattr(textwrap, 'ansilen'):
        return textwrap.ansilen(s)
    else:
        return len(s)


[docs]class Dimension(object): """ The Dimension class encapsulates the height and width of a component. Args: width (int): the width of the Dimension, in columns. height (int): the height of the Dimension, in rows. dimension (Dimension, optional): an existing Dimension from which to duplicate the height and width. """ def __init__(self, width=0, height=0, dimension=None): self.width = width self.height = height if dimension is not None: self.width = dimension.width self.height = dimension.height
class MenuHeader(MenuComponent): """ The menu header section. The menu header contains the top margin, menu top, title/subtitle verticals, bottom padding verticals, and optionally a bottom border to separate the header from the next section. """ def __init__(self, menu_style, max_dimension=None, title=None, title_align='left', subtitle=None, subtitle_align='left', show_bottom_border=False): super(MenuHeader, self).__init__(menu_style, max_dimension) self.title = title self.title_align = title_align self.subtitle = subtitle self.subtitle_align = subtitle_align self.show_bottom_border = show_bottom_border def generate(self): for x in range(0, self.margins.top): yield '' yield self.outer_horizontal_border_top() for x in range(0, self.padding.top): yield self.row() if self.title is not None and self.title != '': yield self.row(content=self.title, align=self.title_align) if self.subtitle is not None and self.subtitle != '': yield self.row() yield self.row(content=self.subtitle, align=self.subtitle_align) for x in range(0, self.padding.bottom): yield self.row() if self.show_bottom_border: yield self.inner_horizontal_border() class MenuTextSection(MenuComponent): """ The menu text block section. A text block section can be used for displaying text to the user above or below the main items section. """ def __init__(self, menu_style, max_dimension=None, text=None, text_align='left', show_top_border=False, show_bottom_border=False): super(MenuTextSection, self).__init__(menu_style, max_dimension) self.text = text self.text_align = text_align self.show_top_border = show_top_border self.show_bottom_border = show_bottom_border def generate(self): if self.show_top_border: yield self.inner_horizontal_border() for x in range(0, self.padding.top): yield self.row() if self.text is not None and self.text != '': yield self.row(content=self.text, align=self.text_align) for x in range(0, self.padding.bottom): yield self.row() if self.show_bottom_border: yield self.inner_horizontal_border() class MenuItemsSection(MenuComponent): """ The menu section for displaying the menu items. """ def __init__(self, menu_style, max_dimension=None, items=None, items_align='left'): super(MenuItemsSection, self).__init__(menu_style, max_dimension) if items is not None: self.__items = items else: self.__items = list() self.items_align = items_align self.__top_border_dict = dict() self.__bottom_border_dict = dict() @property def items(self): return self.__items @items.setter def items(self, items): self.__items = items @property def items_with_bottom_border(self): """ Return a list of the names (the item text property) of all items that should show a bottom border. :return: a list of item names that should show a bottom border. """ return self.__bottom_border_dict.keys() @property def items_with_top_border(self): """ Return a list of the names (the item text property) of all items that should show a top border. :return: a list of item names that should show a top border. """ return self.__top_border_dict.keys() def show_item_bottom_border(self, item_text, flag): """ Sets a flag that will show a bottom border for an item with the specified text. :param item_text: the text property of the item :param flag: boolean specifying if the border should be shown. """ if flag: self.__bottom_border_dict[item_text] = True else: self.__bottom_border_dict.pop(item_text, None) def show_item_top_border(self, item_text, flag): """ Sets a flag that will show a top border for an item with the specified text. :param item_text: the text property of the item :param flag: boolean specifying if the border should be shown. """ if flag: self.__top_border_dict[item_text] = True else: self.__top_border_dict.pop(item_text, None) def generate(self): for x in range(0, self.padding.top): yield self.row() for index, item in enumerate(self.items): if item.text in self.items_with_top_border: yield self.inner_horizontal_border() # the length of the separator plus the length of the longest index number indent_size = len(item.index_item_separator) + len(str(len(self.items))) yield self.row(content=item.show(index), align=self.items_align, indent_len=indent_size) if item.text in self.items_with_bottom_border: yield self.inner_horizontal_border() for x in range(0, self.padding.bottom): yield self.row() class MenuFooter(MenuComponent): """ The menu footer section. The menu footer contains the menu bottom, bottom padding verticals, and bottom margin. """ def generate(self): for x in range(0, self.padding.top): yield self.row() yield self.outer_horizontal_border_bottom() for x in range(0, self.margins.bottom): yield '' class MenuPrompt(MenuComponent): """ A string representing the menu prompt for user input. """ def __init__(self, menu_style, max_dimension=None, prompt_string=">>"): super(MenuPrompt, self).__init__(menu_style, max_dimension) self.__prompt = prompt_string @property def prompt(self): return self.__prompt @prompt.setter def prompt(self, prompt): self.__prompt = prompt def generate(self): for x in range(0, self.padding.top): yield '' for line in self.prompt.split(): yield u"{lm}{line} ".format(lm=' ' * self.margins.left, line=line)