display.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. '''
  2. display.py
  3. Various utilities for displaying information such as tables and metered values.
  4. '''
  5. import math, mud
  6. def table_row(info, align="left", caps = "|", space=" ",
  7. center_filler=" ", width=79):
  8. '''display a table row like this:
  9. | info |
  10. '''
  11. # account for color codes
  12. width += info.count("{")*2
  13. fmt = "%s%s%%-%ds%s%s" % (caps, space, width-len(caps)*2-len(space)*2,
  14. space, caps)
  15. if align == "center":
  16. info = info.center(width-len(caps)*2-len(space)*2, center_filler)
  17. elif align == "right":
  18. fmt = "%s%s%%%ds%s%s" % (caps, space, width-len(caps)*2-len(space)*2,
  19. space, caps)
  20. return fmt % info
  21. def table_splitrow(left, right, align="left", caps = "|", space=" ",
  22. center_filler=" ", width=79):
  23. '''display two columns like this:
  24. | left | right |
  25. '''
  26. width -= len(caps)*2 + len(space)*4
  27. linfo = table_row(left, align, "", "", center_filler, width/2)
  28. rinfo = table_row(right, align, "", "", center_filler, width/2)
  29. fmt = "%s%s%%s%s%s%s%%s%s%s" % (caps,space,space,caps,space,space,caps)
  30. return fmt % (linfo, rinfo)
  31. def table_splitrows(left, right, align="left", caps = "|", space=" ",
  32. center_filler=" ", width=79):
  33. """return a list of split rows"""
  34. buf = [ ]
  35. for i in range(max(len(left), len(right))):
  36. lstr = ""
  37. rstr = ""
  38. if i < len(left):
  39. lstr = left[i]
  40. if i < len(right):
  41. rstr = right[i]
  42. buf.append(table_splitrow(lstr, rstr, align, caps, space, center_filler,
  43. width))
  44. return buf
  45. def meter(val,char="{p#",empty=" ",lcap="[",rcap="]",align="left",width=20):
  46. """Return a horizontal meter representing a numeric value ranging between
  47. [0,1]."""
  48. width = width-len(lcap)-len(rcap) + (lcap.count("{")+rcap.count("{"))*2
  49. hatches = int(math.floor(width*abs(val)))
  50. hatches = min(hatches, width)
  51. left = ""
  52. right = ""
  53. # are we dealing with a backwards meter?
  54. left = "".join([char for v in range(hatches)])
  55. right = "".join([empty for v in range(width-hatches)])
  56. if align == "right":
  57. left, right = right, left
  58. return lcap + "{n" + left + right + "{n" + rcap + "{n"
  59. def pagedlist(category_map, order=None, header=None, height=21):
  60. """Display lists of information as flips within a book. category_map is a
  61. mapping between section headers and lists of entries to display for that
  62. category. If you are only displaying one category, have a map from
  63. the section header, Topics, to your list of entries. If the categories
  64. should be displayed in a specific (or partially specific) order, that
  65. can be specified. Header is text that can appear at front of the book
  66. display.
  67. """
  68. buf = [ ]
  69. # split our header into rows if we have one
  70. hrows = [ ]
  71. if header != None:
  72. hrows = mud.format_string(header, False, 76).strip().split("\r\n")
  73. # build our full list of orderings
  74. if order == None:
  75. order = [ ]
  76. for category in category_map.iterkeys():
  77. if not category in order:
  78. order.append(category)
  79. # build our page entries. This includes categories and category items
  80. entries = [ ]
  81. for category in order:
  82. if not category in category_map:
  83. continue
  84. # add a space between categories
  85. if len(entries) > 0:
  86. entries.append("")
  87. entries.append(category.capitalize())
  88. for item in category_map[category]:
  89. entries.append(" %s" % item)
  90. # append our header if we have one
  91. if len(hrows) > 0:
  92. buf.append(table_border)
  93. for hrow in hrows:
  94. buf.append(table_row(hrow))
  95. # build our page contents, one page at a time, until we are out of entries
  96. pages = [ ]
  97. last_cat = None
  98. while len(entries) > 0:
  99. page = [ ]
  100. plen = height - 2 # minus 2 for the borders
  101. # we're still on the first flip of the book; header is displayed
  102. if len(pages) <= 2:
  103. plen -= len(hrows) + 1 # plus 1 for the row above it
  104. # add items to the page until we are full
  105. while len(entries) > 0 and len(page) < plen:
  106. entry = entries.pop(0)
  107. # is this a blank row, and are we at the head of the page?
  108. if entry == "" and len(page) == 0:
  109. continue
  110. # is this a category header?
  111. if not entry.startswith(" "):
  112. last_cat = entry
  113. # are we continuing an old category?
  114. if entry.startswith(" ") and len(page)==0 and last_cat != None:
  115. page.append("%s (cont.)" % last_cat)
  116. page.append(entry)
  117. # did we have anything added to it?
  118. if len(page) > 0:
  119. pages.append(page)
  120. # take our pages by twos and turn them into table rows
  121. i = 0
  122. while i < len(pages):
  123. page1 = pages[i]
  124. page2 = [ ]
  125. if i+1 < len(pages):
  126. page2 = pages[i+1]
  127. # append the rows and page contents
  128. buf.append(table_border)
  129. buf.extend(table_splitrows(page1, page2))
  130. buf.append(table_border)
  131. i += 2
  132. buf.append("")
  133. return buf
  134. # shortcut table elements
  135. table_border = table_row("", "center", "+", "", "-")
  136. table_filler = table_row("")
  137. seperator = table_row("", "center", "-", "", "-")