""" Box drawing utilities for Canvas. The box drawing characters have zero to four lines radiating from the center of the glyph. There are three line types: thin, heavy, and double. These are indicated by 1, 2, and 3 respectively (0 for no line). This code represents the characters as a tuple of 4 integers, (, , , ). This format makes it possible to logically combine characters together, as there is no mathematical relationship in the unicode db. Note that not all combinations are possible. Characters can have a maximum of 2 border types in a single glyph. There are also fewer characters for the "double" line type. """ from __future__ import annotations from functools import lru_cache from typing_extensions import TypeAlias Quad: TypeAlias = "tuple[int, int, int, int]" """Four values indicating the composition of the box character.""" # Yes, I typed this out by hand. - WM BOX_CHARACTERS: dict[Quad, str] = { (0, 0, 0, 0): " ", (0, 0, 0, 1): "╴", (0, 0, 0, 2): "╸", (0, 0, 0, 3): "╸", # (0, 0, 1, 0): "╷", (0, 0, 1, 1): "┐", (0, 0, 1, 2): "┑", (0, 0, 1, 3): "╕", # (0, 0, 2, 0): "╻", (0, 0, 2, 1): "┒", (0, 0, 2, 2): "┓", (0, 0, 2, 3): "╕", # (0, 0, 3, 0): "╻", (0, 0, 3, 1): "╖", (0, 0, 3, 2): "╖", (0, 0, 3, 3): "╗", # (0, 1, 0, 0): "╶", (0, 1, 0, 1): "─", (0, 1, 0, 2): "╾", (0, 1, 0, 3): "╼", # (0, 1, 1, 0): "┌", (0, 1, 1, 1): "┬", (0, 1, 1, 2): "┭", (0, 1, 1, 3): "╤", # (0, 1, 2, 0): "┎", (0, 1, 2, 1): "┰", (0, 1, 2, 2): "┱", (0, 1, 2, 3): "┱", # (0, 1, 3, 0): "╓", (0, 1, 3, 1): "╥", (0, 1, 3, 2): "╥", (0, 1, 3, 3): "╥", # (0, 2, 0, 0): "╺", (0, 2, 0, 1): "╼", (0, 2, 0, 2): "━", (0, 2, 0, 3): "━", # (0, 2, 1, 0): "┍", (0, 2, 1, 1): "┮", (0, 2, 1, 2): "┯", (0, 2, 1, 3): "┯", # (0, 2, 2, 0): "┏", (0, 2, 2, 1): "┲", (0, 2, 2, 2): "┳", (0, 2, 2, 3): "╦", # (0, 2, 3, 0): "╒", (0, 2, 3, 1): "╥", (0, 2, 3, 2): "╥", (0, 2, 3, 3): "╦", # (0, 3, 0, 0): "╺", (0, 3, 0, 1): "╾", (0, 3, 0, 2): "╾", (0, 3, 0, 3): "═", # (0, 3, 1, 0): "╒", (0, 3, 1, 1): "╤", (0, 3, 1, 2): "╤", (0, 3, 1, 3): "╤", # (0, 3, 2, 0): "╒", (0, 3, 2, 1): "╤", (0, 3, 2, 2): "╤", (0, 3, 2, 3): "╤", # (0, 3, 3, 0): "╔", (0, 3, 3, 1): "╦", (0, 3, 3, 2): "╦", (0, 3, 3, 3): "╦", # (1, 0, 0, 0): "╵", (1, 0, 0, 1): "┘", (1, 0, 0, 2): "┙", (1, 0, 0, 3): "╛", # (1, 0, 1, 0): "│", (1, 0, 1, 1): "┤", (1, 0, 1, 2): "┥", (1, 0, 1, 3): "╡", # (1, 0, 2, 0): "╽", (1, 0, 2, 1): "┧", (1, 0, 2, 2): "┪", (1, 0, 2, 3): "┪", # (1, 0, 3, 0): "╽", (1, 0, 3, 1): "┧", (1, 0, 3, 2): "┪", (1, 0, 3, 3): "┪", # (1, 1, 0, 0): "└", (1, 1, 0, 1): "┴", (1, 1, 0, 2): "┵", (1, 1, 0, 3): "┵", # (1, 1, 1, 0): "├", (1, 1, 1, 1): "┼", (1, 1, 1, 2): "┽", (1, 1, 1, 3): "┽", # (1, 1, 2, 0): "┟", (1, 1, 2, 1): "╁", (1, 1, 2, 2): "╅", (1, 1, 2, 3): "╅", # (1, 1, 3, 0): "┟", (1, 1, 3, 1): "╁", (1, 1, 3, 2): "╅", (1, 1, 3, 3): "╅", # (1, 2, 0, 0): "┕", (1, 2, 0, 1): "┶", (1, 2, 0, 2): "┷", (1, 2, 0, 3): "╧", # (1, 2, 1, 0): "┝", (1, 2, 1, 1): "┾", (1, 2, 1, 2): "┿", (1, 2, 1, 3): "┿", # (1, 2, 2, 0): "┢", (1, 2, 2, 1): "╆", (1, 2, 2, 2): "╈", (1, 2, 2, 3): "╈", # (1, 2, 3, 0): "┢", (1, 2, 3, 1): "╆", (1, 2, 3, 2): "╈", (1, 2, 3, 3): "╈", # (1, 3, 0, 0): "╘", (1, 3, 0, 1): "╧", (1, 3, 0, 2): "╧", (1, 3, 0, 3): "╧", # (1, 3, 1, 0): "╞", (1, 3, 1, 1): "╬", (1, 3, 1, 2): "╪", (1, 3, 1, 3): "╪", # (1, 3, 2, 0): "╟", (1, 3, 2, 1): "┾", (1, 3, 2, 2): "┾", (1, 3, 2, 3): "╪", # (1, 3, 3, 0): "╞", (1, 3, 3, 1): "╆", (1, 3, 3, 2): "╆", (1, 3, 3, 3): "╈", # (2, 0, 0, 0): "╹", (2, 0, 0, 1): "┚", (2, 0, 0, 2): "┛", (2, 0, 0, 3): "╛", # (2, 0, 1, 0): "╿", (2, 0, 1, 1): "┦", (2, 0, 1, 2): "┩", (2, 0, 1, 3): "┩", # (2, 0, 2, 0): "┃", (2, 0, 2, 1): "┨", (2, 0, 2, 2): "┫", (2, 0, 2, 3): "╢", # (2, 0, 3, 0): "║", (2, 0, 3, 1): "╢", (2, 0, 3, 2): "╢", (2, 0, 3, 3): "╢", # (2, 1, 0, 0): "┖", (2, 1, 0, 1): "┸", (2, 1, 0, 2): "┹", (2, 1, 0, 3): "┹", # (2, 1, 1, 0): "┞", (2, 1, 1, 1): "╀", (2, 1, 1, 2): "╃", (2, 1, 1, 3): "╃", # (2, 1, 2, 0): "┠", (2, 1, 2, 1): "╂", (2, 1, 2, 2): "╉", (2, 1, 2, 3): "╉", # (2, 1, 3, 0): "╟", (2, 1, 3, 1): "╫", (2, 1, 3, 2): "╫", (2, 1, 3, 3): "╫", # (2, 2, 0, 0): "┗", (2, 2, 0, 1): "┺", (2, 2, 0, 2): "┻", (2, 2, 0, 3): "┻", # (2, 2, 1, 0): "┡", (2, 2, 1, 1): "╄", (2, 2, 1, 2): "╇", (2, 2, 1, 3): "╇", # (2, 2, 2, 0): "┣", (2, 2, 2, 1): "╊", (2, 2, 2, 2): "╋", (2, 2, 2, 3): "╬", # (2, 2, 3, 0): "╠", (2, 2, 3, 1): "╬", (2, 2, 3, 2): "╬", (2, 2, 3, 3): "╬", # (2, 3, 0, 0): "╚", (2, 3, 0, 1): "╩", (2, 3, 0, 2): "╩", (2, 3, 0, 3): "╩", # (2, 3, 1, 0): "╞", (2, 3, 1, 1): "╬", (2, 3, 1, 2): "╬", (2, 3, 1, 3): "╬", # (2, 3, 2, 0): "╞", (2, 3, 2, 1): "╬", (2, 3, 2, 2): "╬", (2, 3, 2, 3): "╬", # (2, 3, 3, 0): "╠", (2, 3, 3, 1): "╬", (2, 3, 3, 2): "╬", (2, 3, 3, 3): "╬", # (3, 0, 0, 0): "╹", (3, 0, 0, 1): "╜", (3, 0, 0, 2): "╜", (3, 0, 0, 3): "╝", # (3, 0, 1, 0): "╿", (3, 0, 1, 1): "┦", (3, 0, 1, 2): "┦", (3, 0, 1, 3): "┩", # (3, 0, 2, 0): "║", (3, 0, 2, 1): "╢", (3, 0, 2, 2): "╢", (3, 0, 2, 3): "╣", # (3, 0, 3, 0): "║", (3, 0, 3, 1): "╢", (3, 0, 3, 2): "╢", (3, 0, 3, 3): "╣", # (3, 1, 0, 0): "╙", (3, 1, 0, 1): "╨", (3, 1, 0, 2): "╨", (3, 1, 0, 3): "╩", # (3, 1, 1, 0): "╟", (3, 1, 1, 1): "╬", (3, 1, 1, 2): "╬", (3, 1, 1, 3): "╬", # (3, 1, 2, 0): "╟", (3, 1, 2, 1): "╬", (3, 1, 2, 2): "╬", (3, 1, 2, 3): "╬", # (3, 1, 3, 0): "╟", (3, 1, 3, 1): "╫", (3, 1, 3, 2): "╫", (3, 1, 3, 3): "╉", # (3, 2, 0, 0): "╙", (3, 2, 0, 1): "╨", (3, 2, 0, 2): "╨", (3, 2, 0, 3): "╩", # (3, 2, 1, 0): "╟", (3, 2, 1, 1): "╬", (3, 2, 1, 2): "╬", (3, 2, 1, 3): "╬", # (3, 2, 2, 0): "╟", (3, 2, 2, 1): "╬", (3, 2, 2, 2): "╬", (3, 2, 2, 3): "╬", # (3, 2, 3, 0): "╟", (3, 2, 3, 1): "╫", (3, 2, 3, 2): "╫", (3, 2, 3, 3): "╬", # (3, 3, 0, 0): "╚", (3, 3, 0, 1): "╩", (3, 3, 0, 2): "╩", (3, 3, 0, 3): "╩", # (3, 3, 1, 0): "╠", (3, 3, 1, 1): "╄", (3, 3, 1, 2): "╄", (3, 3, 1, 3): "╇", # (3, 3, 2, 0): "╠", (3, 3, 2, 1): "╬", (3, 3, 2, 2): "╬", (3, 3, 2, 3): "╬", # (3, 3, 3, 0): "╠", (3, 3, 3, 1): "╊", (3, 3, 3, 2): "╬", (3, 3, 3, 3): "╬", } @lru_cache(1024) def combine_quads(box1: Quad, box2: Quad) -> Quad: """Combine two box drawing quads. Args: box1: Existing box quad. box2: New box quad. Returns: A new box quad. """ top1, right1, bottom1, left1 = box1 top2, right2, bottom2, left2 = box2 return ( top2 or top1, right2 or right1, bottom2 or bottom1, left2 or left1, )