123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- from colorama import Fore, Back, Style
- # see http://xahlee.info/comp/unicode_drawing_shapes.html
- def merge(color_string):
- """ Given a string of colorama ANSI, merge them if you can. """
- return color_string.replace("m\x1b[", ";")
- class Boxes(object):
- """ Boxes makes nice ASCII graphic menus
- Example:
- c1 = merge(Style.BRIGHT + Fore.CYAN)
- c2 = merge(Style.NORMAL + Fore.CYAN)
- # Set the size of the box to 40 (Important!)
- box = Boxes(40, color=c1)
- self.queue_game.put(box.top())
- # format string "{0:^40}".format("Text Centered")
- # This centers the text into the size of the box.
- self.queue_game.put(box.row(c1 + "{0:^40}".format("Scripts")))
- # this draws the middle line. (The line that goes across, but is
- # connected on both sides to the one above it).
- self.queue_game.put(box.middle())
- def menu_item(ch, desc):
- # Again we want the final string to be 40!
- # c1 and c2 (below) take 0 space.
- # We have " " + ch + " " + "-" + " " .. which equals 5
- # So desc needs {:35} to pad out string out to 40 print chars.
- row = " {0}{1} {2}-{3} {4:35}".format(c1, ch, c2, c1, desc)
- # self.queue_game.put(
- # " " + c1 + ch + c2 + " - " + c1 + desc + self.nl
- # )
- self.queue_game.put(box.row(row))
- menu_item("1", "Ports (Trades between two sectors)")
- menu_item("2", "Explore (Strange new sectors)")
- menu_item("3", "Space... the final frontier...")
- menu_item("X", "eXit")
- self.queue_game.put(box.bottom())
- """
- box_styles = (
- # ┌──┐
- # │ │
- # ├──┤
- # └──┘
- {
- "tl": "\xda",
- "tr": "\xbf",
- "top": "\xc4",
- "side": "\xb3",
- "bl": "\xc0",
- "br": "\xd9",
- "ml": "\xc3",
- "mr": "\xb4",
- },
- # ╔══╗
- # ║ ║
- # ╠══╣
- # ╚══╝
- {
- "tl": "\xc9",
- "tr": "\xbb",
- "top": "\xcd",
- "side": "\xba",
- "bl": "\xc8",
- "br": "\xbc",
- "ml": "\xcc",
- "mr": "\xb9",
- },
- # ╒══╕
- # │ │
- # ╞══╡
- # ╘══╛
- {
- "tl": "\xd5",
- "tr": "\xb8",
- "top": "\xcd",
- "side": "\xb3",
- "bl": "\xd4",
- "br": "\xbe",
- "ml": "\xc6",
- "mr": "\xb5",
- },
- # ╓──╖
- # ║ ║
- # ╟──╢
- # ╙──╜
- {
- "tl": "\xd6",
- "tr": "\xb7",
- "top": "\xc4",
- "side": "\xba",
- "bl": "\xd3",
- "br": "\xbd",
- "ml": "\xc7",
- "mr": "\xb6",
- },
- )
- def __init__(self, size: int, color="", style=1, start_nl=True):
- """ Construct box
- size is width of text inside the box.
- (so actual width is size + 2).
- color = Style of color to use.
- If color is blank, we don't use the RESET_ALL.
- style=0 Is double lines.
- start_nl Should we start the top with a newline?
- """
- self.size = size
- self.style = style
- self.color = color
- self.start_nl = start_nl
- # default colors
- # self.c = merge(Style.BRIGHT + Fore.WHITE + Back.BLUE)
- # self.cp = merge(Style.BRIGHT + Fore.YELLOW + Back.BLUE)
- # useful consts
- self.r = Style.RESET_ALL
- self.nl = "\n\r"
- # self.bsb = "\b \b"
- def top(self):
- """ Output the TOP line. """
- if self.color == "":
- c = ""
- r = ""
- else:
- c = self.color
- r = self.r
- s = self.box_styles[self.style]
- if self.start_nl:
- n = self.nl
- else:
- n = ""
- return n + c + s["tl"] + s["top"] * self.size + s["tr"] + r + self.nl
- def middle(self):
- """ Output MIDDLE line.
- This solid line goes completely across.
- The edges connect to the top and bottom.
- """
- if self.color == "":
- c = ""
- r = ""
- else:
- c = self.color
- r = self.r
- s = self.box_styles[self.style]
- return c + s["ml"] + s["top"] * self.size + s["mr"] + r + self.nl
- def row(self, line):
- """ Output content line.
- NOTE: the line length must match the box size.
- Use "{0:30}".format(content) to match size of 30.
- """
- if self.color == "":
- c = ""
- r = ""
- else:
- c = self.color
- r = self.r
- s = self.box_styles[self.style]
- return c + "{0}{1}{2}".format(s["side"], r + line + c, s["side"]) + r + self.nl
- def bottom(self):
- """ Output BOTTOM line. """
- if self.color == "":
- c = ""
- r = ""
- else:
- c = self.color
- r = self.r
- s = self.box_styles[self.style]
- return c + s["bl"] + s["top"] * self.size + s["br"] + r + self.nl
- @staticmethod
- def alert(message, length=0, pad=2, width=78, base="blue", style=1):
- """
- Display alert message
- Example:
- self.queue_game.put(Boxes.alert("Proxy done.", base="green"))
- length: the printable character length.
- If the string contains color codes, you'll need
- to use this so it will be centered properly.
- If not given, len(message) is used.
- pad: The spaces at the front and back of the message.
- width: Defaults to 78 chars wide.
- base: The background color to use for the alert.
- """
- if base == "red":
- color = merge(Style.BRIGHT + Fore.YELLOW + Back.RED)
- elif base == "blue":
- color = merge(Style.BRIGHT + Fore.YELLOW + Back.BLUE)
- elif base == "green":
- color = merge(Style.BRIGHT + Fore.YELLOW + Back.GREEN)
- elif base == "cyan":
- color = merge(Style.BRIGHT + Fore.YELLOW + Back.CYAN)
- elif base == "magenta":
- color = merge(Style.BRIGHT + Fore.YELLOW + Back.MAGENTA)
- else:
- # I don't know.
- color = Style.RESET_ALL
- if length == 0:
- length = len(message)
- box_size = length + pad * 2
- boxpad = " " * pad
- box = Boxes(box_size, color=color, style=style, start_nl=False)
- msg = "{0}{1}{2}{3}".format(color, boxpad, message, boxpad)
- # How much pad to add to the left side?
- left_pad = (width - box_size + 2) // 2
- pad = " " * left_pad
- return "{0}{1}{2}{3}{4}{5}".format(
- pad, box.top(), pad, box.row(msg), pad, box.bottom()
- )
|