00001
00002
00003 class CharGrid(dict):
00004 """ Grid of single characters for drawing ascii art.
00005 Keys are (row,col) """
00006 def __init__(self):
00007 self.maxRow = 0
00008 self.maxCol = 0
00009 self._defaultVal = ' '
00010
00011 def __checkkey(self,key):
00012 """ Make sure key is a valid key """
00013 if not isinstance(key,tuple):
00014 raise Exception("Key must be 2-tuple, got %r"%key)
00015 if not len(key) == 2:
00016 raise Exception("Key must be 2-tuple, got %d-tuple"%len(key))
00017 if not (isinstance(key[0],int) and isinstance(key[1],int)):
00018 raise Exception("Key value must be of type (int,int), got (%s,%s)"%(key[0].__class__.__name__,key[1].__class__.__name__))
00019
00020 def __getitem__(self,key):
00021 """ Get a single character from the grid """
00022 self.__checkkey(key)
00023
00024
00025
00026 if not key in self:
00027 self.maxRow = max(key[0],self.maxRow)
00028 self.maxCol = max(key[1],self.maxCol)
00029 return self._defaultVal
00030 return super(CharGrid,self).__getitem__(key)
00031
00032 def __setitem__(self,key,val):
00033 """ Set a single character or string into the grid starting at key"""
00034 self.__checkkey(key)
00035 if not isinstance(val,str):
00036 raise Exception("Val must be 'str', got %r"%val)
00037 if len(val) < 1:
00038 raise Exception("Val must be at least 1 character long, got %d (%s)"%(len(val),val))
00039
00040 cOffset = 0
00041 for c in val:
00042 row = key[0]
00043 col = key[1]+cOffset
00044
00045 if not (row,col) in self:
00046 self.maxRow = max(row,self.maxRow)
00047 self.maxCol = max(col,self.maxCol)
00048
00049 super(CharGrid,self).__setitem__((row,col),c)
00050 cOffset += 1
00051
00052 def insertRowsAbove(self,row,num):
00053 """ add a new row above 'row' (shifting existing rows down) """
00054 keys = filter(lambda k: k[0] >= row,self.keys())
00055 self.__moveCells(keys,(num,0))
00056
00057 def insertColsToLeft(self,col,num):
00058 """ add a new column to the left of 'col' (shifting existing cols right """
00059 keys = filter(lambda k: k[1] >= col,self.keys())
00060 self.__moveCells(keys,(0,num))
00061
00062 def __moveCells(self,keys,direction):
00063 """ Called by insertRowAbove...
00064 Moves all cells in 'keys' in 'direction'.
00065 Each key is 'keys' specified by (row,col). Direction specified by
00066 (rowOffset,colOffset).
00067 """
00068 while len(keys) > 0:
00069 keys = self.__moveCell(keys[0],keys,direction)
00070
00071 def __moveCell(self,srcKey,keys,direction):
00072 """ Called by __moveCells - recursively moves cells to move srcKey cell """
00073 self.__checkkey(srcKey)
00074 self.__checkkey(direction)
00075 destKey = (srcKey[0]+direction[0],srcKey[1]+direction[1])
00076
00077 if destKey in self:
00078 keys = self.__moveCell(destKey,keys,direction)
00079
00080 self[destKey] = self[srcKey]
00081 self.pop(srcKey)
00082 keys.pop(keys.index(srcKey))
00083 return keys
00084
00085
00086 def __str__(self):
00087 imgbuf = ""
00088 for r in range(self.maxRow+1):
00089 rowbuf = list()
00090 for c in range(self.maxCol+1):
00091 rowbuf.append(self[(r,c)])
00092 imgbuf+= "".join(rowbuf)+"\n"
00093 return imgbuf