''' display.py Various utilities for displaying information such as tables and metered values. ''' import math, mud def table_row(info, align="left", caps = "|", space=" ", center_filler=" ", width=79): '''display a table row like this: | info | ''' # account for color codes width += info.count("{")*2 fmt = "%s%s%%-%ds%s%s" % (caps, space, width-len(caps)*2-len(space)*2, space, caps) if align == "center": info = info.center(width-len(caps)*2-len(space)*2, center_filler) elif align == "right": fmt = "%s%s%%%ds%s%s" % (caps, space, width-len(caps)*2-len(space)*2, space, caps) return fmt % info def table_splitrow(left, right, align="left", caps = "|", space=" ", center_filler=" ", width=79): '''display two columns like this: | left | right | ''' width -= len(caps)*2 + len(space)*4 linfo = table_row(left, align, "", "", center_filler, width/2) rinfo = table_row(right, align, "", "", center_filler, width/2) fmt = "%s%s%%s%s%s%s%%s%s%s" % (caps,space,space,caps,space,space,caps) return fmt % (linfo, rinfo) def table_splitrows(left, right, align="left", caps = "|", space=" ", center_filler=" ", width=79): """return a list of split rows""" buf = [ ] for i in range(max(len(left), len(right))): lstr = "" rstr = "" if i < len(left): lstr = left[i] if i < len(right): rstr = right[i] buf.append(table_splitrow(lstr, rstr, align, caps, space, center_filler, width)) return buf def meter(val,char="{p#",empty=" ",lcap="[",rcap="]",align="left",width=20): """Return a horizontal meter representing a numeric value ranging between [0,1].""" width = width-len(lcap)-len(rcap) + (lcap.count("{")+rcap.count("{"))*2 hatches = int(math.floor(width*abs(val))) hatches = min(hatches, width) left = "" right = "" # are we dealing with a backwards meter? left = "".join([char for v in range(hatches)]) right = "".join([empty for v in range(width-hatches)]) if align == "right": left, right = right, left return lcap + "{n" + left + right + "{n" + rcap + "{n" def pagedlist(category_map, order=None, header=None, height=21): """Display lists of information as flips within a book. category_map is a mapping between section headers and lists of entries to display for that category. If you are only displaying one category, have a map from the section header, Topics, to your list of entries. If the categories should be displayed in a specific (or partially specific) order, that can be specified. Header is text that can appear at front of the book display. """ buf = [ ] # split our header into rows if we have one hrows = [ ] if header != None: hrows = mud.format_string(header, False, 76).strip().split("\r\n") # build our full list of orderings if order == None: order = [ ] for category in category_map.iterkeys(): if not category in order: order.append(category) # build our page entries. This includes categories and category items entries = [ ] for category in order: if not category in category_map: continue # add a space between categories if len(entries) > 0: entries.append("") entries.append(category.capitalize()) for item in category_map[category]: entries.append(" %s" % item) # append our header if we have one if len(hrows) > 0: buf.append(table_border) for hrow in hrows: buf.append(table_row(hrow)) # build our page contents, one page at a time, until we are out of entries pages = [ ] last_cat = None while len(entries) > 0: page = [ ] plen = height - 2 # minus 2 for the borders # we're still on the first flip of the book; header is displayed if len(pages) <= 2: plen -= len(hrows) + 1 # plus 1 for the row above it # add items to the page until we are full while len(entries) > 0 and len(page) < plen: entry = entries.pop(0) # is this a blank row, and are we at the head of the page? if entry == "" and len(page) == 0: continue # is this a category header? if not entry.startswith(" "): last_cat = entry # are we continuing an old category? if entry.startswith(" ") and len(page)==0 and last_cat != None: page.append("%s (cont.)" % last_cat) page.append(entry) # did we have anything added to it? if len(page) > 0: pages.append(page) # take our pages by twos and turn them into table rows i = 0 while i < len(pages): page1 = pages[i] page2 = [ ] if i+1 < len(pages): page2 = pages[i+1] # append the rows and page contents buf.append(table_border) buf.extend(table_splitrows(page1, page2)) buf.append(table_border) i += 2 buf.append("") return buf # shortcut table elements table_border = table_row("", "center", "+", "", "-") table_filler = table_row("") seperator = table_row("", "center", "-", "", "-")